在这个问题上,有人在评论中建议我不要使用malloc的结果。即,我应该这样做:
int *sieve = malloc(sizeof(*sieve) * length);
而不是:
int *sieve = (int *) malloc(sizeof(*sieve) * length);
为什么会这样?
在这个问题上,有人在评论中建议我不要使用malloc的结果。即,我应该这样做:
int *sieve = malloc(sizeof(*sieve) * length);
而不是:
int *sieve = (int *) malloc(sizeof(*sieve) * length);
为什么会这样?
当前回答
返回的类型为void*,可以将其转换为所需类型的数据指针,以便可以取消引用。
其他回答
这就是GNU C库参考手册所说的:
您可以将malloc的结果存储到任何指针变量中强制转换,因为ISO C会自动将类型void*转换为另一个必要时的指针类型。但演员阵容在上下文中是必要的而不是赋值运算符,或者如果您可能希望代码运行在传统C。
事实上,ISO C11标准(第47页)是这么说的:
如果分配成功,则返回的指针将适当对齐它可以分配给指向任何类型对象的指针基本对齐要求,然后用于访问这样的对象或此类对象的数组(直到空间被显式释放)
在C语言中,您得到了从void*到任何其他(数据)指针的隐式转换。
返回的类型为void*,可以将其转换为所需类型的数据指针,以便可以取消引用。
我加入强制转换只是为了表示对类型系统中的丑陋漏洞的不满,这种漏洞允许像以下代码片段这样的代码在没有诊断的情况下编译,即使没有强制转换来导致错误的转换:
double d;
void *p = &d;
int *q = p;
我希望这不存在(而且在C++中也不存在),所以我投了。它代表了我的品味和我的编程政治。我不仅投了一个指针,而且有效地投了一张选票,并淘汰了愚蠢的恶魔。如果我真的不能摆脱愚蠢,那么至少让我用一种抗议的姿态来表达这样做的愿望。
事实上,一个好的做法是用返回无符号char*的函数包装malloc(和朋友),并且基本上不要在代码中使用void*。如果需要指向任何对象的通用指针,请使用char*或无符号char*,并在两个方向上进行强制转换。也许,可以放松的一点是使用memset和memcpy等函数而不进行强制转换。
关于强制转换和C++兼容性的主题,如果您编写代码以使其同时编译为C和C++(在这种情况下,当将malloc的返回值分配给void*以外的其他对象时,您必须强制转换malloc),您可以为自己做一件非常有用的事情:当编译为C++时,可以使用宏强制转换为C++风格的强制转换,但当编译为C:
/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif
如果您遵循这些宏,那么对代码库进行简单的grep搜索以查找这些标识符将显示所有强制转换的位置,因此您可以检查其中是否有错误。
然后,如果您经常使用C++编译代码,那么它将强制使用适当的强制转换。例如,如果您使用strip_qual只是为了删除常量或volatile,但是程序的变化导致现在涉及到类型转换,那么您将得到一个诊断,并且您必须使用强制转换的组合来获得所需的转换。
为了帮助您遵守这些宏,GNUC++(而不是C!)编译器有一个漂亮的功能:一个可选的诊断程序,它针对所有C样式强制转换的出现而生成。
-Wold-style-cast (C++ and Objective-C++ only) Warn if an old-style (C-style) cast to a non-void type is used within a C++ program. The new-style casts (dynamic_cast, static_cast, reinterpret_cast, and const_cast) are less vulnerable to unintended effects and much easier to search for.
如果您的C代码编译为C++,则可以使用此-Wold样式的转换选项来查找可能在代码中出现的(类型)转换语法的所有情况,并通过使用上述宏中的适当选项(或组合,如果需要)来替换它来跟踪这些诊断。
这种转换处理是在“Clean C”中工作的唯一最大的独立技术理由:结合了C和C++方言,这反过来又在技术上证明了强制转换malloc的返回值是合理的。
在C语言中,不需要强制转换malloc的返回值。malloc返回的指向void的指针会自动转换为正确的类型。但是,如果您想用C++编译器编译代码,则需要强制转换。社区中的首选替代方案是使用以下方法:
int *sieve = malloc(sizeof *sieve * length);
另外,如果你改变了筛子的类型,你就不用担心改变表达式的右边。
正如人们所指出的那样,铸件是不好的。尤其是指针强制转换。