参考:https://blog.csdn.net/chenyq991/article/details/74015270
https://blog.csdn.net/ixsea/article/details/6693178#commentBox
什么是类型安全?
类型安全很大程度上可以等价于内存安全,类型安全的代码不会试图访问自己没被授权的内存区域。
2、“类型安全”常被用来形容编程语言,其根据在于该门编程语言是否提供保障类型安全的机制;有的时候也用“类型安全”形容某个程序,判别的标准在于该程序是否隐含类型错误。
3、类型安全的编程语言与类型安全的程序之间,没有必然联系。好的程序员可以使用类型不那么安全的语言写出类型相当安全的程序,相反的,差一点儿的程序员可能使用类型相当安全的语言写出类型不太安全的程序。绝对类型安全的编程语言暂时还没有。
2、C的类型安全
C语言不是类型安全的语言,原因如下:
1)很多情况下,会存在类型隐式转换;
2)malloc函数返回的是void 的空类型指针,通常需要这样的显示类型转换char pStr=(char*)malloc(100sizeof(char)),类型匹配没有问题。但如果出现int pInt=(int*)malloc(100*sizeof(char))这样的转换,可能会带来一些问题,但C并不会提示。
当然,在有些情况下表现还是类型安全的,当从一个结构体指针转换成另一个结构体指针时,编译器会报错,除非显式转换。
3、C++的类型安全
**C++也不是类型安全的语言,**但远比C更具类型安全。相比于C,提供了一些安全保障机制:
1)用操作符new来申请内存,严格与对象类型匹配,而malloc是void *;
2)函数参数为void *的可以改写成模板,模板支持运行时检查参数类型;
3)使用const代替define来定义常量,具有类型、作用域,而不是简单的文本替换;
4)使用inline代替define来定义函数,结合函数的重载,在类型安全的前提下可以支持多种类型,如果改写成模板,会更安全;
5)提供dynamic_cast使得转换过程更安全。
尽管如此,但如果使用空类型指针或者在两个不同类型指针间做强制转换,很可能引发类型不安全的问题。
4、总结
想要保证程序的类型安全,尽量避免使用空类型指针,尽量不对不同类型的指针做强制转换。
举例:
C语言的类型安全举例
C只在局部上下文中表现出类型安全,比如试图从一种结构体的指针转换成另一种结构体的指针时,编译器将会报告错误,除非使用显式类型转换。然而,C中相当多的操作是不安全的。以下是两个十分常见的例子:
(1)printf格式输出
int main()
{
printf("%d\n",10);
system("pause");
return 0;
}
上面的代码很简单,printf函数中,%d与10匹配,结果正确。
稍作修改:
int main()
{
printf("%f\n",10);
system("pause");
return 0;
}
%f浮点数与10并不匹配,但是编译通过,执行也没报错,但是结果却是:
0.000000
请按任意键继续. . .
更进一步,把%f修改为%s,编译通过,执行将报错Access Violation。
C++语言的类型安全举例
即便如此,C++也不是绝对类型安全的编程语言。如果使用不得当,同样无法保证类型安全。比如下面两个例子:
int i=5;
void* pInt=&i;
double d=(*(double*)pInt);
cout<<d<<endl;
输入结果不是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*,尽量不对两种类型指针做强制转换。