C/C++的类型安全

zz/2024/7/23 5:31:41

什么是类型安全?
类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域。“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制;有的时候也用“类型安全”形容某个程序,判别的标准在于该程序是否隐含类型错误。类型安全的编程语言与类型安全的程序之间,没有必然联系。好的程序员可以使用类型不那么安全的语言写出类型相当安全的程序,相反的,差一点儿的程序员可能使用类型相当安全的语言写出类型不太安全的程序。绝对类型安全的编程语言暂时还没有。
C语言的类型安全
C只在局部上下文中表现出类型安全,比如试图从一种结构体的指针转换成另一种结构体的指针时,编译器将会报告错误,除非使用显式类型转换。然而,C中相当多的操作是不安全的。以下是两个十分常见的例子:
(1)printf格式输出

/* - print.cpp
* version:1.1
*/
int main()
{
printf("%d\n",10);
system("pause");
return 0;
}

上面的代码很简单,printf函数中,%d与10匹配,结果正确。
稍作修改:

/* - print.cpp
* version:1.2
*/
int main()
{
printf("%f\n",10);
system("pause");
return 0;
}

%f浮点数与10并不匹配,但是编译通过,执行也没报错,但是结果却是:
0.000000
请按任意键继续. . .
更进一步,把%f修改为%s,编译通过,执行将报错Access Violation。
(2)malloc函数的返回值
malloc是C中进行内存分配的函数,它的返回类型是void*即空类型指针,常常有这样的用法char* pStr=(char*)malloc(100*sizeof(char)),这里明显做了显式的类型转换。类型匹配尚且没有问题,但是一旦出现int* pInt=(int*)malloc(100*sizeof(char))就很可能带来一些问题,而这样的转换C并不会提示错误。
C++的类型安全
如果C++使用得当,它将远比C更有类型安全性。相比于C,C++提供了一些新的机制保障类型安全:
(1)操作符new返回的指针类型严格与对象匹配,而不是void*;
(2)C中很多以void*为参数的函数可以改写为C++模板函数,而模板是支持类型检查的;
(3)引入const关键字代替#define constants,它是有类型、有作用域的,而#define constants只是简单的文本替换;
(4)一些#define宏可被改写为inline函数,结合函数的重载,可在类型安全的前提下支持多种类型,当然改写为模板也能保证类型安全;
(5)C++提供了dynamic_cast关键字,使得转换过程更加安全,因为dynamic_cast比static_cast涉及更多具体的类型检查。
即便如此,C++也不是绝对类型安全的编程语言。如果使用不得当,同样无法保证类型安全。比如下面两个例子:

int i=5;
void* pInt=&i;
double d=(*(double*)pInt);
cout<<d<<endl; <="" p="">

输入结果不是5,而意想不到的结果:-9.25596e+061。又比如:

#include<iostream>  
using namespace std;  
class Parent  
{  
};  
class Child1:public Parent  
{  
public:  int i;  Child1(int e):i(e)  {  }  
};  
class Child2:public Parent  
{  
public:  double d;  Child2(double e):d(e)  {  }  
};  
int main()  
{  Child1 c1(5);  Child2 c2(4.1);  Parent* pp;  Child1* pc1;  pp=&c1;  pc1=(Child1*)pp;  //#1 强制转换,由于类型仍然为Child1*,不造成错误  cout<<pc1->i<<endl;  pp=&c2;  pc1=(Child1*)pp;  //#2 强制转换,且类型发生变化,将造成错误  cout<<pc1->i<<endl;  system("pause");  return 0;  
} 

结果如下:
5
1717986918
请按任意键继续. . .
上面两个例子之所以引起类型不安全的问题,是因为程序员使用不得当。第一个例子用到了空类型指针void*,第二个例子则是在两个类型指针之间进行强制转换。因此,想保证程序的类型安全性,应尽量避免使用空类型指针void*,尽量不对两种类型指针做强制转换。


转载自:http://blog.pureisle.net/archives/985.html


http://www.ngui.cc/zz/2769451.html

相关文章

嵌入式动态内存分配过程

参考&#xff1a;http://blog.chinaunix.net/space.php?uid20312618&doblog&cuid1815216 一、概述&#xff1a; 动态内存分配&#xff0c;特别是开发者经常接触的Malloc/Free接口的实现&#xff0c;对许多开发者来说&#xff0c;是一个永远的话题&#xff0c;而且有时…

阿里HR筛选简历

上周发了一个阿里内推的帖子&#xff0c;没想到短时间内就收到了成百上千封简历。 我仔仔细细地看了每一封简历&#xff0c;附带有Github地址的我也点进去仔细看了代码。 最终我留下了30%的简历&#xff0c;而且这30%中只有10%的本科生。 所有通过内推初步筛选的小伙伴会在8月3…

点到线段的最短距离——矢量法

最近在看recast&detour源码的时候有遇到许多数学上的算法问题&#xff0c;特此记录&#xff0c;以便以后查看。 矢量法推导&#xff1a; 求点P到线段AB的最短距离。分成以下三种情况(a),(b),(c)。 &#xff08;勘误&#xff1a;dPC 应该是在 ∠PAB和∠PBA都小于90的情况…

Restore IP Addresses---LeetCode

题目要求&#xff1a;输入一串字符串&#xff0c;输出可能组成的ip地址。 先申请题意&#xff0c;弄清需求&#xff1a; 会存在不是数字的字符串吗&#xff1f;都是数字 10.10.10.01 最后一个01&#xff0c;符合要求吗&#xff1f;不符合要求。 leetcode上的示例答案&#x…

Recast Detour 寻路引擎学习建议

1.初步了解Recast&Detour,完成工程的下载和生成运行 http://www.stevefsp.org/projects/rcndoc/prod/index.html 2.了解Recast-导航数据的创建 看源代码中的Sample_SoloMesh.handleBuild 函数 http://www.critterai.org/projects/nmgen_study/overview.html 此英文文档…

Failed to load Assets/Plugins/xxx.dll with error

遇到这个错误&#xff0c;首先检查看提示的路径下面是否真的有 xxx.dll 如果有&#xff0c;那就是这个dll所引用的其他的库你电脑上没有&#xff0c;本地电脑的环境问题&#xff0c;把相关的dll拷贝到系统目录或者特定的目录下就可。 如何查看你缺少什么库&#xff1a; 下载一…

std::lambda小记

目录 不同形式的语法说明 [ capture ] 例子 lambda是C11中才引入的新特性&#xff0c;能定义匿名对象&#xff0c;而不必定义独立的函数和函数对象。 在介绍函数对象的for_each例子中&#xff0c;如果不用创建函数对象&#xff0c;可以使用下面 std::for_each(dest.begin()…

std::bind小记

当std::bind函数&#xff08;是一个函数模版&#xff09;&#xff0c;用来绑定函数的某些参数并生成一个新的std::function对象。 如何来确定绑定的是函数的第几个参数&#xff0c;引入std::placeholders命名空间&#xff1a; _1,函数调用的第一个参数&#xff0c; _2第2个参…

win10 ‘XXX’不是内部或者外部命令,也不是可执行的程序

比如说 ‘Python’不是内部或者外部命令&#xff0c;也不是可执行的程序 比如说 ‘svn ’不是内部或者外部命令&#xff0c;也不是可执行的程序 没有给可执行程序设置Path环境变量 如下图进行 我的电脑右键选择属性&#xff0c;然后依此选择。把需要执行的exe&#xff0c;比如…

汇编指令和寄存器

《汇编语言》比较旧的书了&#xff0c;讲的都是实模式下的 8086 cpu 《软件调试》比较新的书 以及分析dump文件的时候的例子。 目的是看懂代码的反汇编&#xff0c;设计到汇编指令&#xff0c;相关的硬件如寄存器存储器等。 有一些寄存器的常用名字还是记住的好&#xff0c;…