26

可能的重复:
什么是类型安全的?
什么是类型安全?

我正在阅读有关 C++ 向量的内容,有人提到C 中memcpyprintf函数不是类型安全的。文章在这里:http://en.wikipedia.org/wiki/Vector_(C%2B%2B)

问题:用简单的英语来说,什么是类型安全以及“类型安全”的替代方案是什么?

4

10 回答 10

33

类型安全意味着编译器可以检查您是否使用了正确的类型。例如,如果您正在使用printf,您可能会通过编写以下代码意外地使程序崩溃:

printf("The meaning of life is %s", 42);

因为 42 是整数,而不是字符串。

于 2010-01-26T15:31:33.710 回答
12

类型安全意味着编译器将帮助检查您是否混合(不兼容)数据类型。

例如,当您调用 时memcpy,函数(和编译器)仅在内存中看到两个指针,并且会愉快地开始复制数据。这意味着您可以像这样混合不兼容的数据类型:

SomeClass a;
AnotherClass b;
memcpy((void*)&a, (void*)&b, sizeof(b));

获得类型安全性的方法有很多。您可以使用模板并围绕 mempcy() 进行包装,确保两个指针指向相同的数据类型,或者您可以使用其他方式。

由于您已经在使用 STL 中的向量,因此您已经在使用或多或少的类型安全实现。

于 2010-01-26T15:47:30.693 回答
8

类型安全控制编译器检查变量是否为正确类型的使用。C 在数据类型安全方面非常松散,例如,这实际上是在 ANSI C 标准中,声明数据类型将发生类型提升char,本作业中的示例将对此进行说明,

char ch = 32; /* that is a space character accordingly to ASCII */
int n = ch + 3;

注意ch变量是如何被“提升”为 type 的int。这是合法的,但如果这是您所暗示的,则需要仔细检查。

诸如 C# 编译器之类的编译器不允许这种情况发生,这就是为什么在 C 中使用 cast 运算符的原因,例如:

int n = (int)3.1415926535f;

除了挑剔之外,这是一个 pi 值,发生的情况是 的值n将是 3。

以上用于说明类型安全性,并且 C 在这方面非常宽松。

现代语言中的类型安全更加严格,例如Java、C#,为了约束变量的使用和含义。PHP 是松散类型的一个很好的例子,你可以这样做:

$myvar = 34;
$myvar = $myvar + "foo";

$myvar整数,还是浮点数,还是字符串。这里的类型安全并不是很清楚可能导致错误的意图是什么,以及一个愉快的调试会话试图找出正在发生的事情。

希望这可以帮助

于 2010-01-26T15:52:14.833 回答
3

既然你在维基百科上:输入安全

粗略地说,类型安全意味着该语言禁止您意外混淆您的类型。

memcpy不是类型安全的,因为您可以轻松地将一些内存复制intchar数组中并最终得到无意义的数据。printf不是类型安全的,因为您可以提供%i带有字符串的格式说明符;同样,该字符串将被解释为 anint并且您最终会得到垃圾。(顺便说一下,VC++ 编译器某些情况下会检查格式字符串。)

std::vector<T>是类型安全的,因为它只允许您将给定类型的值T放入其中。(当然,您可以进行显式类型转换,但关键是您必须明确地做一些不安全的事情)。

于 2010-01-26T15:42:10.790 回答
1

“类型安全”意味着编译器检查您是否使用正确的类型做正确的事情(例如,如果您尝试将 Banana 视为橙色,或将字符串提供给期望输出整数的函数,则会触发编译器错误) .

类型安全(大多数情况下)在void*进入图片时会立即出现 - 它是一个可以指向任何东西的指针(完全不知道所涉及的类型),并且语言完全在程序员手中(对于例如,avoid*除了被强制转换回原始类型之外,对任何东西都没有什么好处;它可以表示任何东西,但在使用它之前你必须知道它是什么)。

类型不安全也与 printf 等可变参数函数一起使用(编译器不关心有多少参数以及它们的类型是什么 - 再次由调用者确保格式字符串与参数及其类型匹配) .

memcpy 的类型安全替代方案(用于数组和容器)可能是std::copy-<algorithm>如果所有涉及的类型都满足某些要求,它可以根据 memmove 实现,否则它会执行分配 - 对于某些类,如果你绕过它们的公共,你可以破坏某些不变量接口,然后在内存中移动/复制它们(例如,我想如果你用 memcpy 复制它,任何具有非平凡复制构造函数的类都会出现异常行为)。

CI/O 例程的类型安全替代方案是 iostreams(如果您想要格式字符串的好处,boost::format)。

于 2010-01-26T15:43:59.623 回答
1

“类型安全”使用“类型系统”来确保错误不会在程序中传播。例如,在没有类型安全的情况下,可能会(默默地)以某种不合需要的方式将字符串类型添加到浮点类型。

在您谈论的实例中,memcpy()printf(),缺乏类型安全是由于函数如何处理它们的参数。例如,使用memcpy(arg1, arg2, len),从内存地址arg2开始的len字节将被复制到内存地址arg1 ,无论arg1指向多少字节,这可能会覆盖程序的其他部分。

对于类型安全的替代方案,请查看构造函数cout

事实上,查看整个 C++ FAQ Lite

于 2010-01-26T15:44:28.663 回答
1

这意味着如果您尝试以对该类型没有意义的方式使用该类型,编译器将不会生成任何警告。例如,以下是未定义的行为,实际上会将指针的位复制到浮点数的位中,在那里它们绝对没有意义。如果sizeof(char*)> sizeof(float),它将覆盖恰好位于其上方的任何内存位置f

float f;
char *c = someString();
memcpy(&f, &c, sizeof(char*));
于 2010-01-26T15:44:37.797 回答
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 期望一个字符串作为第二个参数,但得到一个浮点数。

于 2010-01-26T15:44:47.097 回答
0

memcpy 函数的签名是

void *memcpy (void* destination, const void* source, size_t num);

因此,正如您所看到的,它不假设与复制相关的指针,它们只是指针。因此,例如,如果您想将一个范围复制ints到一个范围内的floats编译器不会抱怨这一点。

类型安全是一种工具,可帮助开发人员通过防止某种错误代码被编译(和最近执行)来避免某些错误。它分析源代码的语义方面,以检查类型和类型之间的转换是否一致。

这意味着什么?这意味着如果您的程序通过了类型检查阶段,您可以确保不会在运行时生成某些类型的错误。

当然,有时您需要强制不执行此检查,这就是为什么您可以使用强制转换来强制执行您想要的操作。想想另一个例子malloc:它被定义为

void* malloc (size_t size);

所以当你想分配一个指针时floats,例如你这样做:

float* ptr = (float*)malloc(sizeof(float*)*COUNT);

您被迫将函数的结果强制转换为,float*否则类型检查会发现 a 的分配,void*float*void*通用而无法分配,因此:TYPE CHECK FAIL!

这就是为什么memcpy不是类型安全的。它不检查任何东西,它只是从一个指针复制到另一个指针。

于 2010-01-26T15:50:41.567 回答
-1

答案的简短版本:

class Person;

person.DoSomething(); // This is type safe.

void * p = &person; // You can now start doing unsafe things with p.

您不能将 Person 传递给 memcpy。它只知道和关心内存。字节。

于 2010-01-26T15:46:59.820 回答