我输入malloc的结果吗?


12 Answers

在C中,你不需要施加malloc的返回值。 由malloc返回的void指针自动转换为正确的类型。 但是,如果您希望使用C ++编译器编译代码,则需要执行强制转换。 社区中的首选替代方案是使用以下内容:

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

如果您更改sieve的类型, sieve可以让您不必担心更改表达式的右侧。

正如人们指出的那样,演员阵容不好。 特别指针转换。

Question

这个问题中 ,有人在comment中建议我不应该使用malloc的结果,即

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

而不是:

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

为什么会这样呢?




在此添加所有信息; 这就是GNU C库参考手册所说的:

您可以将malloc的结果存储到任何指针变量中,而无需malloc转换,因为ISO C会在必要时自动将类型void *转换为另一种类型的指针。 但是,除了赋值运算符或者您可能希望代码运行在传统的C中,这种转换是非常必要的。

事实上ISO C11标准 (p347)这样说:

如果分配成功,则返回的指针被适当地对齐,以便它可以被分配给具有基本对齐要求的任何类型的对象的指针,然后用于在分配的空间中访问这样的对象或这样的对象的数组(直到空间被明确释放)




人们习惯了GCC和Clang被宠坏了。 这并不是那么好。

多年来,我一直非常害怕我被要求使用的令人惊叹的老化编译器。 企业和管理人员通常采用超保守的方式来改变编译器,甚至不会测试新编译器(具有更好的标准符合性和代码优化)是否可以在他们的系统中工作。 工作开发人员的实际情况是,当你编写代码时,你需要覆盖你的基础,不幸的是,如果你无法控制哪些编译器可以应用到你的代码中,那么铸造mallocs是一个好习惯。

我还建议许多组织应用他们自己的编码标准,并且应该是人们如果定义的方法遵循的方法。 在没有明确指导的情况下,我倾向于最有可能编译的地方,而不是奴隶制的标准。

根据目前的标准来看,这是没有必要的论点是非常有效的。 但是这个论点忽略了现实世界的实用性。 我们不是在一个完全按照当时标准统治的世界中编码,而是根据我所称的“本地管理现实领域”的实际情况编写代码。 而这种弯曲和扭曲超过了空间时间。 :-)

因人而异。

我倾向于将malloc作为防御性操作来考虑。 不漂亮,不完美,但通常是安全的。 (说实话,如果你还没有包含stdlib.h,那么你就比铸造malloc更麻烦了!)。




不强制转换malloc的结果,因为它返回void* ,并且void*可以指向任何数据类型。




你不会投出malloc的结果,因为这样做会给代码添加无意义的混乱。

人们投射malloc的结果最常见的原因是他们不确定C语言是如何工作的。 这是一个警告信号:如果你不知道特定的语言机制如何工作,那么不要猜测。 查看它或询问。

一些评论:

  • 一个void指针可以转换为任何其他指针类型,而不需要显式强制转换(C11 6.3.2.3和6.5.16.1)。

  • 然而,C ++将不允许在void*和另一个指针类型之间进行隐式转换。 所以在C ++中,演员阵容将是正确的。 但是如果你用C ++编程,你应该使用new而不是malloc()。 你不应该使用C ++编译器编译C代码。

    如果您需要使用相同的源代码支持C和C ++,请使用编译器开关标记差异。 不要试图用相同的代码来表达两种语言标准,因为它们不兼容。

  • 如果C编译器因为忘记包含头文件而无法找到某个函数,那么您将得到一个有关该编译器/链接器的错误。 因此,如果您忘记包含<stdlib.h> ,那么这将毫无意义,您将无法构建您的程序。

  • 在遵循超过25年的标准版本的古代编译器上,忘记包含<stdlib.h>会导致危险的行为。 因为在那个古老的标准中,没有可见原型的函数将返回类型隐式转换为int 。 然后从malloc中明确输出结果会隐藏这个错误。

    但这真的不是问题。 你没有使用25年前的电脑,那么你为什么要使用25年前的编译器?




A void pointer is a generic pointer and C supports implicit conversion from a void pointer type to other types, so there is no need of explicitly typecasting it.

However, if you want the same code work perfectly compatible on a C++ platform, which does not support implicit conversion, you need to do the typecasting, so it all depends on usability.




在C语言中,void指针可以分配给任何指针,这就是为什么你不应该使用类型转换。 如果你想“类型安全”的分配,我可以推荐下面的宏函数,我总是在我的C项目中使用这些函数:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

有了这些,你可以简单地说

NEW_ARRAY(sieve, length);

对于非动态数组,第三个必备函数宏是

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

这使得数组循环更安全,更方便:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}



The casting of malloc is unnecessary in C but mandatory in C++.

  • Casting is unnecessary in C because of void * is automatically and safely promoted to any other pointer type in this case.
  • It can hide an error if you forgot to include <stdlib.h> . This can cause crashes.
  • If pointers and integers are differently sized, then you're hiding a warning by casting and might lose bits of your returned address.



The concept behind void pointer is that it can be casted to any data type that is why malloc returns void. Also you must be aware of automatic typecasting. So it is not mandatory to cast the pointer though you must do it. It helps in keeping the code clean and helps debugging




Wikipedia

铸件的优点

  • 包括转换可能允许C程序或函数编译为C ++。

  • 该转换允许1989年以前版本的malloc最初返回一个char *。

  • 如果指针远离malloc()调用(尽管现代编译器和静态分析器可以在不需要强制转换的情况下对此类行为发出警告),Casting可以帮助开发人员确定类型调整中的不一致情况。

铸造的缺点

  • 在ANSI C标准下,演员阵容是多余的。

  • 添加转换可能会掩盖未能包含stdlib.h头文件,其中会找到malloc的原型。 在没有malloc原型的情况下,该标准要求C编译器假定malloc返回一个int。 如果没有强制转换,则将此整数分配给指针时发出警告; 然而,在演员阵容中,这个警告并没有产生,隐藏了一个bug。 在某些体系结构和数据模型(如64位系统上的LP64,其中long和指针为64位且int为32位)中,此错误实际上可能导致未定义的行为,因为隐式声明的malloc返回32位数据, bit值,而实际定义的函数返回一个64位值。 根据调用约定和内存布局,这可能导致堆栈粉碎。 在现代编译器中,这个问题不太可能被忽视,因为它们一致地发出警告,指出已经使用了未声明的函数,所以仍会出现警告。 例如,GCC的默认行为是显示一条警告,该警告读取“不兼容的隐含声明的内置函数”,无论演员是否存在。

  • 如果指针的类型在其声明中发生更改,还可能需要更改调用malloc的所有行并进行强制转换。

尽管malloc没有铸造是首选方法,大多数有经验的程序员都选择它 ,但应该使用你喜欢的任何人知道这些问题。

即:如果您需要将C程序编译为C ++(尽管这些是独立的语言),您应该使用malloc进行强制转换。




No, you don't cast the result of malloc() .

In general, you don't cast to or from void * .

A typical reason given for not doing so is that failure to #include <stdlib.h> could go unnoticed. This isn't an issue anymore for a long time now as C99 made implicit function declarations illegal, so if your compiler conforms to at least C99, you will get a diagnostic message.

But there's a much stronger reason not to introduce unnecessary pointer casts:

In C, a pointer cast is almost always an error . This is because of the following rule ( §6.5 p7 in N1570, the latest draft for C11):

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:
— a type compatible with the effective type of the object,
— a qualified version of a type compatible with the effective type of the object,
— a type that is the signed or unsigned type corresponding to the effective type of the object,
— a type that is the signed or unsigned type corresponding to a qualified version of the effective type of the object,
— an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or
— a character type.

This is also known as the strict aliasing rule . So the following code is undefined behavior :

long x = 5;
double *p = (double *)&x;
double y = *p;

And, sometimes surprisingly, the following is as well:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

Sometimes, you do need to cast pointers, but given the strict aliasing rule , you have to be very careful with it. So, any occurrence of a pointer cast in your code is a place you have to double-check for its validity . Therefore, you never write an unnecessary pointer cast.

tl;dr

In a nutshell: Because in C, any occurrence of a pointer cast should raise a red flag for code requiring special attention, you should never write unnecessary pointer casts.

Side notes:

  • There are cases where you actually need a cast to void * , eg if you want to print a pointer:

    int x = 5;
    printf("%p\n", (void *)&x);
    

    The cast is necessary here, because printf() is a variadic function, so implicit conversions don't work.

  • In C++, the situation is different. Casting pointer types is somewhat common (and correct) when dealing with objects of derived classes. Therefore, it makes sense that in C++, the conversion to and from void * is not implicit. C++ has a whole set of different flavors of casting.




正如其他人所说的那样,C不需要它,而是C ++。 如果你认为你要用C ++编译器编译你的C代码,出于这个原因,你可以使用一个宏来代替,如:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

这样你仍然可以用非常紧凑的方式写出它:

int *sieve = NEW(int, 1);

它将编译为C和C ++。




返回的类型是void *,可以将其转换为所需类型的数据指针以便可解引用。




Related