在这个问题上,有人在评论中建议我不要使用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);
为什么会这样?
当前回答
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语言的理解)告诉我,这是绝对没有必要的,但只用于绝对具体,并让学生们养成绝对具体的心态。从本质上讲,强制转换不会改变它的工作方式,它完全按照它所说的做,分配内存,强制转换不影响它,你会得到相同的内存,即使你错误地将它强制转换为其他东西(并以某种方式规避编译器错误),C也会以同样的方式访问它。
编辑:铸造有一定的意义。当您使用数组表示法时,生成的代码必须知道要到达下一个元素的开头,需要前进多少个内存位置,这是通过强制转换实现的。通过这种方式,您可以知道,对于double,您可以提前8个字节,而对于int,则可以提前4个字节,依此类推。因此,如果您使用指针表示法,则不会产生任何影响,在数组表示法中,这是必要的。
你会选演员,因为:
它使您的代码在C和C++之间更具可移植性,正如SO的经验所示,许多程序员声称,当他们真正用C++(或C加本地编译器扩展)编写时,他们是在用C编写。如果不这样做,可能会隐藏一个错误:请注意所有的so示例,它们混淆了何时写入类型*和类型**。它会让你注意不到你没有#包含一个合适的头文件,这一想法让你错过了树的森林。这与说“不要担心你没能让编译器抱怨没有看到原型的事实——讨厌的stdlib.h才是真正需要记住的重要东西!”它强制进行额外的认知交叉检查。它将(所谓的)所需类型放在您对该变量的原始大小所做的算术旁边。我敢打赌,你可以做一个SO研究,表明malloc()错误在有演员时被捕获的速度要快得多。与断言一样,揭示意图的注释可以减少错误。以机器可以检查的方式重复自己的行为通常是一个好主意。事实上,这就是断言,使用强制转换就是断言。断言仍然是我们获得正确代码的最通用技术,因为图灵多年前就提出了这个想法。
习惯于GCC和Clang的人被宠坏了。外面不是很好。
这些年来,我被要求使用的过时的编译器吓坏了。公司和管理者通常采用极端保守的方法来更改编译器,甚至不会测试新的编译器(具有更好的标准遵从性和代码优化)是否能在他们的系统中工作。对于正在工作的开发人员来说,实际情况是,当你在编写代码时,你需要覆盖你的基础,不幸的是,如果你不能控制什么编译器可以应用于你的代码,那么使用mallocs是一个好习惯。
我还建议许多组织应用自己的编码标准,如果定义了编码标准,那么这应该是人们遵循的方法。在缺乏明确指导的情况下,我倾向于选择最有可能在任何地方编译,而不是盲目地遵守某个标准。
根据现行标准,这是不必要的,这一论点是非常有效的。但这一论点忽略了现实世界的现实性。在一个完全由当今标准统治的世界里,我们并没有编码,而是由我喜欢称之为“地方管理的现实领域”的实用性来控制。这比太空时代更加弯曲和扭曲
YMMV。
我倾向于将使用malloc作为防御操作。不漂亮,不完美,但总体安全。(老实说,如果你没有包含stdlib.h,那么你会遇到比强制执行malloc更多的问题!)。
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++。强制转换允许最初返回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的结果。