在这个问题上,有人在评论中建议我不要使用malloc的结果。即,我应该这样做:

int *sieve = malloc(sizeof(*sieve) * length);

而不是:

int *sieve = (int *) malloc(sizeof(*sieve) * length);

为什么会这样?


当前回答

void指针是泛型指针,C支持从void指针类型到其他类型的隐式转换,因此不需要显式类型转换。

然而,如果您希望相同的代码在不支持隐式转换的C++平台上完美兼容,则需要进行类型转换,因此这一切都取决于可用性。

其他回答

在C语言中,不需要强制转换malloc的返回值。malloc返回的指向void的指针会自动转换为正确的类型。但是,如果您想用C++编译器编译代码,则需要强制转换。社区中的首选替代方案是使用以下方法:

int *sieve = malloc(sizeof *sieve * length);

另外,如果你改变了筛子的类型,你就不用担心改变表达式的右边。

正如人们所指出的那样,铸件是不好的。尤其是指针强制转换。

malloc的主要问题是获得正确的大小。

malloc()返回的内存是非类型的,由于简单的强制转换,它不会神奇地获得有效的类型。

我想这两种方法都很好,选择应该取决于程序员的意图。

如果为类型分配内存,则使用强制转换。

ptr=(T*)malloc(sizeof(T));

如果为给定指针分配内存,则不要使用强制转换。

ptr=malloc(sizeof*ptr);

Ad 1

第一种方法通过为给定类型分配内存,然后将其强制转换以确保分配给正确的指针,从而确保正确的大小。如果使用了不正确的ptr类型,则编译器将发出警告/错误。如果ptr的类型被更改,那么编译器将指出代码需要重构的地方。

此外,第一种方法可以组合成类似于C++中新运算符的宏。

#define NEW(T) ((T*)malloc(sizeof(T)))
...
ptr = NEW(T);

此外,如果ptr为void*,则此方法有效。

Ad 2

第二个方法不关心类型,它通过从指针的类型中获取数据来确保正确的大小。这种方法的主要优点是,每当ptr的类型发生变化时,都可以自动调整存储大小。它可以在重构时节省一些时间(或错误)。

缺点是,如果ptr为空,则该方法不起作用,但它可能被认为是一件好事。而且它不适用于C++,因此不应在C++程序将要使用的头中的内联函数中使用。

就我个人而言,我更喜欢第二种选择。

尽可能在C语言中编程时最好做的事情是:

通过C编译器编译程序,并打开所有警告-Wall并修复所有错误和警告确保没有声明为auto的变量然后使用带有-Wall和-std=C++11的C++编译器对其进行编译。修复所有错误和警告。现在再次使用C编译器进行编译。您的程序现在应该在没有任何警告的情况下编译,并且包含更少的错误。

这个过程使您可以利用C++严格的类型检查,从而减少错误的数量。特别是,此过程强制您包含stdlib.否则您将得到

malloc未在此范围内声明

并且还强制你使用malloc的结果,否则你会得到

从void*到T的转换无效*

或者你的目标类型是什么。

用C而不是C++编写的唯一好处是

C具有明确规定的ABIC++可能会生成更多代码[异常、RTTI、模板、运行时多态性]

请注意,在理想情况下,当使用C所共有的子集和静态多态特性时,第二个缺点应该消失。

对于那些觉得C++严格规则不方便的人,我们可以使用带有推断类型的C++11特性

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

你会选演员,因为:

它使您的代码在C和C++之间更具可移植性,正如SO的经验所示,许多程序员声称,当他们真正用C++(或C加本地编译器扩展)编写时,他们是在用C编写。如果不这样做,可能会隐藏一个错误:请注意所有的so示例,它们混淆了何时写入类型*和类型**。它会让你注意不到你没有#包含一个合适的头文件,这一想法让你错过了树的森林。这与说“不要担心你没能让编译器抱怨没有看到原型的事实——讨厌的stdlib.h才是真正需要记住的重要东西!”它强制进行额外的认知交叉检查。它将(所谓的)所需类型放在您对该变量的原始大小所做的算术旁边。我敢打赌,你可以做一个SO研究,表明malloc()错误在有演员时被捕获的速度要快得多。与断言一样,揭示意图的注释可以减少错误。以机器可以检查的方式重复自己的行为通常是一个好主意。事实上,这就是断言,使用强制转换就是断言。断言仍然是我们获得正确代码的最通用技术,因为图灵多年前就提出了这个想法。

来自维基百科:

铸造的优点包括强制转换可以允许C程序或函数编译为C++。强制转换允许最初返回char*的1989年以前版本的malloc。如果目标指针类型发生变化,强制转换可以帮助开发人员识别类型大小的不一致,特别是如果指针声明的位置远离malloc()调用(尽管现代编译器和静态分析器可以在不需要强制转换的情况下警告此类行为)。铸造的缺点根据ANSI C标准,铸件是多余的。添加强制转换可能会掩盖将标头stdlib.h包含在找到了malloc的原型。如果没有malloc的原型,标准要求C编译器假设malloc返回一个int。如果没有强制转换,则警告为当该整数被分配给指针时发出;然而,随着演员,这个警告没有产生,隐藏了一个bug。在某些情况下体系结构和数据模型(例如64位系统上的LP64,其中long和指针为64位,int为32位),此错误可能实际上导致未定义的行为,正如隐式声明的malloc返回32位值,而实际定义的函数返回64位值。取决于调用约定和内存布局,这可能会导致堆栈损坏。这个问题不太可能在现代编译器中不被注意,因为它们统一地生成警告已使用未声明的函数,因此警告将仍然出现。例如,GCC的默认行为是显示警告:“内置的不兼容隐式声明函数”,而不管是否存在强制转换。如果指针的类型在其声明时发生了更改,则可以此外,需要更改调用和强制转换malloc的所有行。

尽管malloc不带强制转换是首选方法,大多数有经验的程序员都会选择它,但在意识到问题后,您应该使用任何您喜欢的方法。

即:如果您需要将C程序编译为C++(尽管它是一种单独的语言),则必须强制转换使用malloc的结果。