我正在阅读有关c ++向量的内容,并且提到C中的memcpy
和printf
函数不是类型安全的。文章:http://en.wikipedia.org/wiki/Vector_(C%2B%2B)。
问题:简单的英语,什么是类型安全,什么是“类型安全”替代品?
答案 0 :(得分:26)
类型安全意味着编译器可以检查您是否使用了正确的类型。例如,如果您使用的是printf
,则可能会通过以下方式意外崩溃您的程序:
printf("The meaning of life is %s", 42);
因为42是整数,而不是字符串。
答案 1 :(得分:10)
Type safety表示编译器将帮助检查您是否混合(不兼容)数据类型。
例如,当你调用memcpy
时,函数(和编译器)只在内存中看到两个指针,并且很乐意开始复制数据。这意味着您可以混合不兼容的数据类型,如下所示:
SomeClass a;
AnotherClass b;
memcpy((void*)&a, (void*)&b, sizeof(b));
有许多方法可以获得类型安全性。您可以使用模板并围绕mempcy()创建一个包装器,确保两个指针指向相同的数据类型,或者您可以使用其他方式。
由于您已经在使用STL中的向量,因此您已经在使用或多或少类型安全的实现。
答案 2 :(得分:8)
类型安全性控制编译器的使用,检查变量是否为正确类型。 C在数据类型安全方面非常松散,例如,这实际上是ANSI C标准,它声明类型提升将发生在数据类型char
中,此分配中的一个示例将解释这一点,
char ch = 32; /* that is a space character accordingly to ASCII */
int n = ch + 3;
注意ch
变量如何“提升”为int
类型。这是合法的,但如果这就是你所暗示的,则需要进一步检查。
C#编译器之类的编译器不会允许这种情况发生,这就是为什么在C语言中使用强制转换运算符的原因,例如:
int n = (int)3.1415926535f;
除了挑剔之外,这是一个pi值,会发生什么,n
的值是3。
以上用于说明类型安全性,C在这方面非常松散。
现代语言中的类型安全性更严格,例如Java,C#,以限制变量的用法和含义。 PHP是松散打字的一个很好的例子,你可以这样做:
$myvar = 34;
$myvar = $myvar + "foo";
是$myvar
一个整数,或者它是一个浮点还是一个字符串。这里的类型安全性不是很明确,可能导致错误的意图是什么,以及试图找出正在发生的事情的快乐调试会话。
希望这有帮助
答案 3 :(得分:2)
因为你无论如何都在维基百科上:Type safety。
大致说,类型安全意味着该语言禁止您意外混淆您的类型。
memcpy
不是类型安全的,因为您可以轻松地将某些int
的内存复制到char
数组中,最终会出现无意义的数据。 printf
不是类型安全的,因为您可以使用字符串提供%i
格式说明符;再次,该字符串将被解释为int
,你最终会得到垃圾。 (顺便提一下,VC ++编译器在某些情况下检查格式字符串。)
std::vector<T>
是类型安全的,因为它只允许您将给定类型T
的值放入其中。 (当然,您可以进行明确的类型转换,但关键是您必须明确关于做一些非类型安全的事情。)
答案 4 :(得分:1)
“类型安全”意味着编译器检查您正在使用正确的类型执行正确的操作(例如,如果您尝试将Banana视为橙色,则触发编译器错误,或者为期望输出的函数提供字符串整数)。
当void*
进入图片时,类型安全(大多数)就会出现在窗外 - 它是一个可以指向任何东西的指针(完全没有意识到所涉及的类型),并且语言会随之发生它完全在程序员的手中(例如,void*
除了被回归到原始类型之外几乎没有什么好处;它可以代表任何东西,但你必须知道它是什么之后你可以使用它)。
类型不安全也可以使用像varf这样的可变函数(编译器不关心有多少参数以及它们的类型是什么 - 再次由调用者来确保格式字符串与参数匹配,他们的类型)。
memcpy(对于数组和容器)的类型安全替代可以是std::copy
中的<algorithm>
- 如果所有涉及的类型满足某些要求,它可以以memmove的形式实现,否则它执行赋值 - 如果绕过它们的公共接口并且只是在内存中移动/复制它们,你可以使用某些类来破坏某些不变量(例如,我认为任何具有非平凡复制构造函数的类如果你复制它就会行为不端用memcpy)。
C / I例程的类型安全替代方法是iostream(如果您希望获得格式字符串的好处,boost::format
)。
答案 5 :(得分:1)
“类型安全”使用“类型系统”来确保错误不会在程序中传播。例如,如果没有类型安全性,则可能(以静默方式)以某种不合需要的方式将字符串类型添加到浮点类型。
在你正在谈论的实例中, memcpy()和 printf(),缺乏类型安全性是由于函数如何处理它们的参数。例如,使用 memcpy(arg1,arg2,len),从内存地址 arg2 开始的 len 字节将被复制到内存地址 arg1 ,无论 arg1 指向多少字节,都可能会覆盖程序的其他部分。
对于类型安全的替代方案,请查看constructors和cout.
答案 6 :(得分:1)
这意味着如果您尝试以对该类型没有意义的方式使用类型,编译器将不会生成警告。例如,以下是未定义的行为,并且在实践中将指针的位复制到浮点的位中,在那里它们完全没有意义。如果sizeof(char*)
&gt; sizeof(float)
,它会覆盖恰好位于f
所在位置的所有内存位置。
float f;
char *c = someString();
memcpy(&f, &c, sizeof(char*));
答案 7 :(得分:0)
类型安全是指一种编码范例,它强制每个变量在编译时具有专用类型,例如int a = 4; double d = 100.0; struct ms {char s;} mystruct;
变量的类型永远不会“丢失”。如果要将其类型从a更改为b,则必须定义显式或隐式转换。
printf
不类型安全,因为您在可变参数列表中传递参数:
float f = 1.f;
printf("This is a float: %f\nAnd this is a string: %s",f,f);
printf
不知道她收到了哪种价值观。实现使用格式字符串来查找,但如果字符串错误,则实现没有机会找到它,因为在编译时没有可用的类型信息。上面的printf
调用最有可能最终发生灾难性的事 - printf期望一个字符串作为第二个参数,但得到一个浮点数。
答案 8 :(得分:0)
答案的简短版本:
class Person;
person.DoSomething(); // This is type safe.
void * p = &person; // You can now start doing unsafe things with p.
您无法将人员传递给memcpy。它只知道并关心记忆。字节。
答案 9 :(得分:0)
memcpy函数的签名是
void *memcpy (void* destination, const void* source, size_t num);
因此你可以看到它没有假设任何涉及副本的指针,它们只是指针。因此,如果您想将ints
的范围复制到floats
范围,编译器就不会抱怨。
类型安全是一种工具,可以帮助开发人员通过防止某些错误代码被编译(并最近执行)来避免某些错误。它分析了源代码的语义方面,以检查类型和类型之间的转换是否一致。
这是什么意思?这意味着如果您的程序通过类型检查阶段,您可以确保在运行时不会生成 CERTAIN KIND 错误。
当然有时你需要强制执行此检查,这就是为什么你可以使用强制转换来强制你想要的东西。想想另一个例子malloc
:它被定义为
void* malloc (size_t size);
所以当你想要分配一个指向floats
的指针时,例如:
float* ptr = (float*)malloc(sizeof(float*)*COUNT);
您被迫将函数的结果强制转换为float*
,否则类型检查会找到void*
到float*
的分配,但void*
过于通用如此分配: TYPE CHECK FAIL!
这就是为什么memcpy
不是类型安全的原因。它不会检查任何内容,只是从指针复制到另一个指针。