In this question, someone suggested in a comment that I should not cast the result of malloc
, i.e.
在这个问题中,有人在评论中建议我不要使用malloc的结果。
int *sieve = malloc(sizeof(int) * length);
rather than:
而不是:
int *sieve = (int *) malloc(sizeof(int) * length);
Why would this be the case?
为什么会这样?
27 个解决方案
#1
1886
No; you don't cast the result, since:
没有;你没有预测结果,因为:
- It is unnecessary, as
void *
is automatically and safely promoted to any other pointer type in this case. - 这是不必要的,因为在这种情况下,void *会自动安全地升级到任何其他指针类型。
- It adds clutter to the code, casts are not very easy to read (especially if the pointer type is long).
- 它给代码增加了混乱,强制类型转换不太容易读(特别是当指针类型很长时)。
- It makes you repeat yourself, which is generally bad.
- 它会让你重复你自己,这通常是不好的。
- It can hide an error if you forgot to include
<stdlib.h>
. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code). Consider what happens if pointers and integers are differently sized; then you're hiding a warning by casting and might lose bits of your returned address. Note: as of C11 implicit functions are gone from C, and this point is no longer relevant since there's no automatic assumption that undeclared functions returnint
. -
如果忘记包含
,则可以隐藏错误。这可能导致崩溃(或者更糟的是,直到稍后在代码的某些完全不同的部分发生崩溃时才导致崩溃)。考虑如果指针和整数大小不同会发生什么;然后,您通过强制转换来隐藏警告,并可能丢失返回的地址。注意:对于C11隐函数,这一点不再相关,因为没有自动假设未声明的函数返回int。
As a clarification, note that I said "you don't cast", not "you don't need to cast". In my opinion, it's a failure to include the cast, even if you got it right. There are simply no benefits to doing it, but a bunch of potential risks, and including the cast indicates that you don't know about the risks.
澄清一下,注意我说过“你不需要演员”,而不是“你不需要演员”。在我看来,即使你选对了演员阵容,这也是个失败。这样做没有什么好处,但是有很多潜在的风险,包括演员阵容表明你不知道这些风险。
Also note, as commentators point out, that the above talks about straight C, not C++. I very firmly believe in C and C++ as separate languages.
还请注意,正如评论员指出的,上面提到的是直接的C,而不是c++。我非常坚定地相信C和c++是独立的语言。
To add further, your code needlessly repeats the type information (int
) which can cause errors. It's better to dereference the pointer being used to store the return value, to "lock" the two together:
要进一步添加,您的代码不必要地重复可能导致错误的类型信息(int)。最好是取消用于存储返回值的指针,将两者“锁定”在一起:
int *sieve = malloc(length * sizeof *sieve);
This also moves the length
to the front for increased visibility, and drops the redundant parentheses with sizeof
; they are only needed when the argument is a type name. Many people seem to not know (or ignore) this, which makes their code more verbose. Remember: sizeof
is not a function! :)
这也将长度移到前面,以增加可见性,并删除带有sizeof的冗余括号;只有当参数是类型名时才需要它们。许多人似乎不知道(或忽略)这一点,这使得他们的代码更加冗长。记住:sizeof不是一个函数!:)
While moving length
to the front may increase visibility in some rare cases, one should also pay attention that in the general case, it should be better to write the expression as:
虽然在一些罕见的情况下,将长度移动到前面可能会增加可见性,但也要注意,在一般情况下,最好将表达式写成:
int *sieve = malloc(sizeof *sieve * length);
Since keeping the sizeof
first, in this case, ensures multiplication is done with at least size_t
math.
由于首先保持sizeof,在本例中,确保乘法至少使用size_t数学完成。
Compare: malloc(sizeof *sieve * length * width)
vs. malloc(length * width * sizeof *sieve)
the second may overflow the length * width
when width
and length
are smaller types than size_t
.
比较:malloc(sizeof *sieve * length * width)与malloc(length * width * sizeof *筛子)当宽度和长度小于size_t时,第二个可能会溢出length * width。
#2
315
In C, you don't need to cast the return value of malloc
. The pointer to void returned by malloc
is automagically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed. A preferred alternative among the community is to use the following:
在C中,不需要强制转换malloc的返回值。malloc返回的空指针自动转换为正确的类型。但是,如果您希望您的代码使用c++编译器进行编译,则需要强制转换。社区中比较可取的一种选择是使用下列方法:
int *sieve = malloc(sizeof *sieve * length);
which additionally frees you from having to worry about changing the right-hand side of the expression if ever you change the type of sieve
.
另外,如果您改变了筛子的类型,您就不必担心表达式的右边。
Casts are bad, as people have pointed out. Specially pointer casts.
正如人们所指出的,演员阵容很糟糕。特别是指针类型强制转换。
#3
281
You do cast, because:
你做演员,因为:
- It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions).
- 它使您的代码在C和c++之间更具可移植性,正如经验所显示的,许多程序员声称,当他们真正使用c++(或c++本地编译器扩展)编写代码时,他们使用的是C语言。
- Failing to do so can hide an error: note all the SO examples of confusing when to write
type *
versustype **
. - 如果不这样做,就会隐藏一个错误:注意所有的例子,比如在写类型*和类型**时混淆。
- The idea that it keeps you from noticing you failed to
#include
an appropriate header file misses the forest for the trees. It's the same as saying "don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes -- that pesky stdlib.h is the REAL important thing to remember!" - 它阻止你注意到你失败了的想法包括一个适当的头文件忽略了森林的树木。这就好比说“不要担心你没能让编译器抱怨没有看到原型——那个讨厌的stdlib。”h是需要记住的最重要的东西!
- It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that
malloc()
bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs. - 它迫使人们进行额外的认知交叉检查。它将(所谓的)期望类型放在您对该变量的原始大小所做的算术旁边。我敢打赌,您可以做一个SO研究,表明malloc() bug在有cast时被捕获得更快。与断言一样,揭示意图的注释可以减少bug。
- Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago.
- 用一种机器可以检查的方式重复你自己通常是个好主意。事实上,这就是断言,而使用cast就是断言。断言仍然是我们获得代码正确的最通用的技术,因为图灵在很多年以前就提出了这个想法。
#4
142
As other stated, it is not needed for C, but for C++. If you think you are going to compile your C code with a C++ compiler, for which reasons ever, you can use a macro instead, like:
如前所述,它不是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
That way you can still write it in a very compact way:
这样你仍然可以把它写得很紧凑:
int *sieve = NEW(int, 1);
and it will compile for C and C++.
它将编译为C和c++。
#5
92
In C you can implicitly convert a void pointer to any other kind of pointer, so a cast is not necessary. Using one may suggest to the casual observer that there is some reason why one is needed, which may be misleading.
在C语言中,可以隐式地将空指针转换为任何其他类型的指针,因此不需要强制转换。使用其中一种可能会向一般的观察者暗示,有一些原因需要使用它,这可能会产生误导。
#6
89
From the Wikipedia
从*
Advantages to casting
优势,铸造
Including the cast may allow a C program or function to compile as C++.
包括强制转换可以允许C程序或函数以c++的形式编译。
The cast allows for pre-1989 versions of malloc that originally returned a char *.
演员允许在1989年以前的malloc版本中返回一个char *。
Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the malloc() call (although modern compilers and static analyzers can warn on such behaviour without requiring the cast).
如果目标指针类型改变,强制转换可以帮助开发人员识别类型大小的不一致性,特别是当指针被声明在远离malloc()调用的地方时(尽管现代编译器和静态分析器可以在不需要强制转换的情况下对这种行为发出警告)。
Disadvantages to casting
缺点铸造
Under the ANSI C standard, the cast is redundant.
在ANSI C标准下,铸件是多余的。
Adding the cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assume malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug. On certain architectures and data models (such as LP64 on 64-bit systems, where long and pointers are 64-bit and int is 32-bit), this error can actually result in undefined behaviour, as the implicitly declared malloc returns a 32-bit value whereas the actually defined function returns a 64-bit value. Depending on calling conventions and memory layout, this may result in stack smashing. This issue is less likely to go unnoticed in modern compilers, as they uniformly produce warnings that an undeclared function has been used, so a warning will still appear. For example, GCC's default behaviour is to show a warning that reads "incompatible implicit declaration of built-in function" regardless of whether the cast is present or not.
添加强制转换可能会掩盖包含头stdlib的失败。在其中发现了malloc的原型。在没有malloc原型的情况下,标准要求C编译器假设malloc返回一个int,如果没有类型转换,则在将这个整数分配给指针时发出警告;但是,在cast中,这个警告没有产生,隐藏了一个bug。在某些体系结构和数据模型(比如64位系统上的LP64,在那里,long和指针是64位的,而int是32位的),这个错误实际上会导致未定义的行为,因为隐式声明的malloc返回一个32位的值,而实际定义的函数返回64位值。根据调用约定和内存布局,这可能导致堆栈崩溃。在现代编译器中,这个问题不太可能被忽略,因为它们一致地产生警告,表示使用了未声明的函数,因此仍然会出现警告。例如,GCC的默认行为是显示一个警告,该警告的内容是“不兼容的内置函数的隐式声明”,而不管转换是否存在。
If the type of the pointer is changed at its declaration, one may also, need to change all lines where malloc is called and cast.
如果指针的类型在其声明时发生了更改,您也可能需要更改调用malloc并强制转换的所有行。
Although malloc without casting is preferred method and most experienced programmers choose it, you should use whichever you like having aware of the issues.
尽管malloc不强制转换是首选方法,并且大多数经验丰富的程序员都选择它,但是您应该使用您喜欢的任何方法来了解这些问题。
i.e: If you need to compile C program as C++(Although those are separate language) you should use malloc
with casting.
我。e:如果你需要把C程序编译成c++(虽然它们是独立的语言),你应该使用malloc和cast。
#7
81
You don't cast the result of malloc, because doing so adds pointless clutter to your code.
您不会对malloc的结果进行强制转换,因为这样做会给您的代码增加毫无意义的混乱。
The most common reason why people cast the result of malloc is because they are unsure about how the C language works. That's a warning sign: if you don't know how a particular language mechanism works, then don't take a guess. Look it up or ask on Stack Overflow.
人们之所以选择malloc的结果,最常见的原因是他们不确定C语言是如何工作的。这是一个警告信号:如果你不知道一种特定的语言机制是如何工作的,那么不要去猜测。查找或询问堆栈溢出。
Some comments:
一些评论:
-
A void pointer can be converted to/from any other pointer type without an explicit cast (C11 6.3.2.3 and 6.5.16.1).
空指针可以转换为/from任何其他指针类型,而无需显式转换(C11 6.3.2.3和6.5.16.1)。
-
C++ will however not allow an implicit cast between
void*
and another pointer type. So in C++, the cast would have been correct. But if you program in C++, you should usenew
and not malloc(). And you should never compile C code using a C++ compiler.但是c++不允许在void*和另一个指针类型之间进行隐式转换。所以在c++中,cast是正确的。但是如果使用c++编程,应该使用new而不是malloc()。而且您永远不应该使用c++编译器编译C代码。
If you need to support both C and C++ with the same source code, use compiler switches to mark the differences. Do not attempt to sate both language standards with the same code, because they are not compatible.
如果需要使用相同的源代码同时支持C和c++,可以使用编译器开关来标记差异。不要试图用相同的代码来满足这两种语言标准,因为它们不兼容。
-
If a C compiler cannot find a function because you forgot to include the header, you will get a compiler/linker error about that. So if you forgot to include
<stdlib.h>
that's no biggie, you won't be able to build your program.如果一个C编译器不能找到一个函数,因为您忘记包含header,那么您将得到一个编译器/链接器错误。因此,如果您忘记包含
。这没什么大不了的,你不能建立你的程序。 -
On ancient compilers that follow a version of the standard which is more than 25 years old, forgetting to include
<stdlib.h>
would result in dangerous behavior. Because in that ancient standard, functions without a visible prototype implicitly converted the return type toint
. Casting the result from malloc explicitly would then hide away this bug.在遵循标准版本(该标准已有25年以上的历史)的古代编译器上,忘记包含
会导致危险的行为。因为在那个古老的标准中,没有可见原型的函数隐式地将返回类型转换为int类型。 。h>But that is really a non-issue. You aren't using a 25 years old computer, so why would you use a 25 years old compiler?
但这真的是一个无关紧要的问题。你不是在使用一台25岁的电脑,那你为什么要使用一台25岁的编译器呢?
#8
80
In C you get an implicit conversion from void*
to any other (data) pointer.
在C中,您将得到从void*到任何其他(数据)指针的隐式转换。
#9
60
Casting the value returned by malloc()
is not necessary now, but I'd like to add one point that seems no one has pointed out:
现在不需要对malloc()返回的值进行强制转换,但我想补充一点,似乎没有人指出:
In the ancient days, that is, before ANSI C provides the void *
as the generic type of pointers, char *
is the type for such usage. In that case, the cast can shut down the compiler warnings.
在古代,也就是说,在ANSI C提供void *作为指针的泛型类型之前,char *是这种用法的类型。在这种情况下,强制转换可以关闭编译器警告。
Reference: C FAQ
参考:C常见问题解答
#10
46
It is not mandatory to cast the results of malloc
, since it returns void*
, and a void*
can be pointed to any datatype.
由于malloc返回void*,并且void*可以指向任何数据类型,所以不强制强制强制转换malloc的结果。
#11
42
Just adding my experience, studying computer engineering I see that the two or three professors that I have seen writing in C always cast malloc, however the one I asked (with an immense CV and understanding of C) told me that it is absolutely unnecessary but only used to be absolutely specific, and to get the students into the mentality of being absolutely specific. Essentially casting will not change anything in how it works, it does exactly what it says, allocates memory, and casting does not effect it, you get the same memory, and even if you cast it to something else by mistake (and somehow evade compiler errors) C will access it the same way.
只是增加我的经验,学习计算机工程我看到两个或三个教授,我看到写在C总是malloc,然而我问(一个巨大的简历和理解C)告诉我,这是完全不必要的,但只有曾经是绝对明确,并得到学生的心态绝对是特定的。本质上铸造不会改变任何东西在它是如何工作的,它就是它说,内存分配,和铸造并不影响它,你得到同样的记忆,即使你丢给别的误(和某种程度上逃避编译器错误)C将以相同的方式访问它。
Edit: Casting has a certain point. When you use array notation, the code generated has to know how many memory places it has to advance to reach the beginning of the next element, this is achieved through casting. This way you know that for a double you go 8 bytes ahead while for an int you go 4, and so on. Thus it has no effect if you use pointer notation, in array notation it becomes necessary.
编辑:选角有一定的意义。当您使用数组符号时,生成的代码必须知道需要提前多少内存空间才能到达下一个元素的开头,这是通过转换实现的。这样你就知道,对于一个双字节你要前进8个字节而对于一个整数你要前进4个字节,以此类推。因此,如果使用指针表示法,它没有任何影响,在数组表示法中,它是必要的。
#12
27
The returned type is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
返回的类型为void*,可以将其转换为所需的数据指针类型,以便可以解除引用。
#13
24
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.
空指针是一个通用指针,C支持隐式转换,从空指针类型到其他类型,因此不需要显式地将它进行类型转换。
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++平台上完全兼容相同的代码,那么您需要进行类型转换,因此这完全取决于可用性。
#14
23
Adding to all the information here; this is what The GNU C Library Reference manual says:
添加到这里的所有信息;以下是GNU C库参考手册的内容:
You can store the result of
malloc
into any pointer variable without a cast, because ISO C automatically converts the typevoid *
to another type of pointer when necessary. But the cast is necessary in contexts other than assignment operators or if you might want your code to run in traditional C.您可以将malloc的结果存储到任何指针变量中,而不需要强制转换,因为ISO C在必要时自动将类型void *转换为另一种类型的指针。但是,除了赋值运算符,或者您可能希望代码在传统的C语言中运行之外,强制转换是必需的。
And indeed the ISO C11 standard (p347) says so:
事实上,ISO C11标准(p347)是这样说的:
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated)
如果分配成功返回的指针是适当对齐,这样它可以分配给一个指针指向任何类型的对象与一个基本定位要求,然后用来访问这样一个对象或类对象数组分配空间(直到空间显式分配)
#15
21
It depends on the programming language and compiler. If you use malloc
in C there is no need to type cast it, as it will automatically type cast, However if your using C++ then you should type cast because malloc
will return a void*
type.
它取决于编程语言和编译器。如果您在C中使用malloc,则不需要键入cast,因为它将自动键入cast,但是如果您使用c++,那么您应该键入cast,因为malloc将返回一个void*类型。
#16
20
In the C language, a void pointer can be assigned to any pointer, which is why you should not use a type cast. If you want "type safe" allocation, I can recommend the following macro functions, which I always use in my C projects:
在C语言中,空指针可以分配给任何指针,这就是为什么不应该使用类型转换。如果你想要“类型安全”的分配,我可以推荐以下宏函数,我在C项目中经常用到:
#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)
With these in place you can simply say
有了这些,你可以简单地说
NEW_ARRAY(sieve, length);
For non-dynamic arrays, the third must-have function macro is
对于非动态数组,第三个必须拥有的函数宏是
#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
which makes array loops safer and more convenient:
使阵列环路更安全、更方便:
int i, a[100];
for (i = 0; i < LEN(a); i++) {
...
}
#17
14
Casting is only for C++ not C.In case you are using a C++ compiler you better change it to C compiler.
铸造只适用于c++而非C。如果你使用c++编译器,你最好把它改成C编译器。
#18
11
People used to GCC and Clang are spoiled. It's not all that good out there.
习惯了GCC和Clang的人被宠坏了。外面并不是那么好。
I have been pretty horrified over the years by the staggeringly aged compilers I've been required to use. Often companies and managers adopt an ultra-conservative approach to changing compilers and will not even test if a new compiler ( with better standards compliance and code optimization ) will work in their system. The practical reality for working developers is that when you're coding you need to cover your bases and, unfortunately, casting mallocs is a good habit if you cannot control what compiler may be applied to your code.
多年来,我一直被要求使用的那些过时的编译器所震惊。通常,公司和管理人员在更改编译器时采用一种极端保守的方法,甚至不会测试一个新的编译器(具有更好的标准遵从性和代码优化)是否在他们的系统中工作。工作开发人员的实际情况是,当您编写代码时,您需要覆盖您的基本内容,不幸的是,如果您无法控制将什么编译器应用到您的代码中,那么抛出mallocs是一个好习惯。
I would also suggest that many organizations apply a coding standard of their own and that that should be the method people follow if it is defined. In the absence of explicit guidance I tend to go for most likely to compile everywhere, rather than slavish adherence to a standard.
我还建议许多组织应用自己的编码标准,如果定义了这个标准,人们应该遵循这个标准。在没有明确指导的情况下,我倾向于在任何地方编译,而不是一味地遵循标准。
The argument that it's not necessary under current standards is quite valid. But that argument omits the practicalities of the real world. We do not code in a world ruled exclusively by the standard of the day, but by the practicalities of what I like to call "local management's reality field". And that's bent and twisted more than space time ever was. :-)
认为在目前的标准下没有必要这样做的观点是很有道理的。但这种观点忽略了现实世界的实际情况。在这个世界上,我们并非完全按照当时的标准行事,而是按照我所称的“地方管理的现实领域”的实际情况行事。它的弯曲和扭曲程度超过了时空。:-)
YMMV.
YMMV。
I tend to think of casting malloc as a defensive operation. Not pretty, not perfect, but generally safe. ( Honestly, if you've not included stdlib.h then you've way more problems than casting malloc ! ).
我倾向于认为使用malloc是一种防御手段。不漂亮,不完美,但总的来说是安全的。(老实说,如果你没有包括stdlib的话。h那么你的问题比铸造malloc要多!)
#19
10
I put in the cast simply to show disapproval of the ugly hole in the type system, which allows code such as the following snippet to compile without diagnostics, even though no casts are used to bring about the bad conversion:
我输入强制转换只是为了表示对类型系统中丑陋的漏洞的反对,它允许不使用强制转换来编译如下代码片段,而不使用任何强制转换:
double d;
void *p = &d;
int *q = p;
I wish that didn't exist (and it doesn't in C++) and so I cast. It represents my taste, and my programming politics. I'm not only casting a pointer, but effectively, casting a ballot, and casting out demons of stupidity. If I can't actually cast out stupidity, then at least let me express the wish to do so with a gesture of protest.
我希望它不存在(在c++中也不存在),所以我进行了cast。它代表了我的品味和我的编程政治。我不仅投了一个指示,而且有效地投了一张选票,并赶走了愚蠢的恶魔。如果我不能真正摆脱愚蠢,那么至少让我以*的姿态来表达我的愿望。
In fact, a good practice is to wrap malloc
(and friends) with functions that return unsigned char *
, and basically never to use void *
in your code. If you need a generic pointer-to-any-object, use a char *
or unsigned char *
, and have casts in both directions. The one relaxation that can be indulged, perhaps, is using functions like memset
and memcpy
without casts.
实际上,一个很好的实践是用返回无符号字符*的函数包装malloc(和friends),并且基本上永远不会在代码中使用void *。如果您需要一个通用的指针到任何对象,请使用char *或unsigned char *,并在两个方向上进行强制转换。一个可以放松的方法是使用像memset和memcpy这样的函数而不用强制类型转换。
On the topic of casting and C++ compatibility, if you write your code so that it compiles as both C and C++ (in which case you have to cast the return value of malloc
when assigning it to something other than void *
), you can do a very helpful thing for yourself: you can use macros for casting which translate to C++ style casts when compiling as C++, but reduce to a C cast when compiling as C:
铸造和c++的主题兼容性,如果你写代码,编译C和c++(在这种情况下,你必须把malloc分配时的返回值不是void *),你可以为自己做一个非常有用的事:您可以使用宏来铸造时转化为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
If you adhere to these macros, then a simple grep
search of your code base for these identifiers will show you where all your casts are, so you can review whether any of them are incorrect.
如果您坚持使用这些宏,那么对这些标识符的代码库进行简单的grep搜索将显示所有的类型转换在哪里,以便您可以检查它们是否有错误。
Then, going forward, if you regularly compile the code with C++, it will enforce the use of an appropriate cast. For instance, if you use strip_qual
just to remove a const
or volatile
, but the program changes in such a way that a type conversion is now involved, you will get a diagnostic, and you will have to use a combination of casts to get the desired conversion.
然后,如果您经常使用c++编译代码,那么它将强制使用适当的cast。例如,如果您使用strip_qual来删除一个const或volatile,但是程序会以这样一种方式改变,即现在涉及到类型转换,您将得到一个诊断,您将不得不使用组合的类型转换来获得所需的转换。
To help you adhere to these macros, the the GNU C++ (not C!) compiler has a beautiful feature: an optional diagnostic which is produced for all occurrences of C style casts.
为了帮助您遵循这些宏,GNU 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.
If your C code compiles as C++, you can use this -Wold-style-cast
option to find out all occurrences of the (type)
casting syntax that may creep into the code, and follow up on these diagnostics by replacing it with an appropriate choice from among the above macros (or a combination, if necessary).
如果你的C代码编译为c++,您可以使用此-Wold-style-cast选项来找出(类型)铸件出现的所有语法,可能会潜入代码,并跟进这些诊断,代之以一个适当的选择从上面的宏(或组合,如果有必要的话)。
This treatment of conversions is the single largest standalone technical justification for working in a "Clean C": the combined C and C++ dialect, which in turn technically justifies casting the return value of malloc
.
这种对转换的处理是在“干净的C”中工作的最大的独立技术理由:C和c++方言的结合,这反过来又在技术上证明了使用malloc的返回值是正确的。
#20
9
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
void指针背后的概念是它可以被强制到任何数据类型,这就是malloc返回void的原因。您还必须了解自动排版。所以虽然你必须这样做,但并不一定要强制转换指针。它有助于保持代码的整洁,并有助于调试
#21
8
The best thing to do when programming in C whenever it is possible:
当用C语言编程时,最好的方法是:
- Make your program compile through a C compiler with all warnings turned on
-Wall
and fix all errors and warnings - 让您的程序通过C编译器编译,并在-Wall上打开所有警告,并修复所有错误和警告
- Make sure there are no variables declared as
auto
- 确保没有声明为auto的变量。
- Then compile it using a C++ compiler with
-Wall
and-std=c++11
. Fix all errors and warnings. - 然后使用带有-Wall和-std=c++11的c++编译器进行编译。修正所有的错误和警告。
- Now compile using the C compiler again. Your program should now compile without any warning and contain fewer bugs.
- 现在再次使用C编译器进行编译。您的程序现在应该没有任何警告,并且包含更少的错误。
This procedure lets you take advantage of C++ strict type checking, thus reducing the number of bugs. In particular, this procedure forces you to include stdlib.h
or you will get
这个过程使您可以利用c++严格的类型检查,从而减少错误的数量。特别是,这个过程强制您包含stdlib。贺南洪你会得到
malloc
was not declared within this scopemalloc不在此范围内声明
and also forces you to cast the result of malloc
or you will get
也迫使你投射malloc的结果,否则你会得到
invalid conversion from
void*
toT*
无效转换从void*到T*
or what ever your target type is.
或者你的目标类型是什么。
The only benefits from writing in C instead of C++ I can find are
用C而不是c++写作的唯一好处是
- C has a well specified ABI
- C有一个明确的ABI
- C++ may generate more code [exceptions, RTTI, templates, runtime polymorphism]
- c++可以生成更多的代码[异常,RTTI,模板,运行时多态性]
Notice that the second cons should in the ideal case disappear when using the subset common to C together with the static polymorphic feature.
注意,在理想情况下,当使用C的公共子集以及静态多态特性时,第二个缺点应该会消失。
For those that finds C++ strict rules inconvenient, we can use the C++11 feature with inferred type
对于那些发现c++严格规则不方便的人,我们可以使用带有推断类型的c++ 11特性
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
#22
8
No, you don't cast the result of malloc()
.
In general, you don't cast to or from void *
.
一般来说,您不会对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.
不这样做的一个典型原因是#include
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):
在C语言中,指针强制转换几乎总是一个错误。这是因为以下规则(§6.5 p7 N1570,最新的草案为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.对象只能通过具有以下类型之一的lvalue表达式访问其存储值:——一种兼容的有效类型对象,——一个合格的版本的类型兼容的有效类型对象,——一种符号(或无符号类型对应的有效类型对象,——一种符号(或无符号类型对应一个合格的版本的有效的类型的对象,-一种集合或联合类型,在其成员(递归地包括子集合或包含的联合的成员)中包含上述类型之一,或——字符类型。
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.
简而言之:因为在C语言中,任何指针强制转换的出现都应该引起需要特别注意的代码的注意,所以不应该编写不必要的指针强制转换。
Side notes:
边注:
-
There are cases where you actually need a cast to
void *
, e.g. 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.在这里,cast是必需的,因为printf()是一个可变的函数,所以隐式转换不起作用。
-
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++中,对void *的转换不是隐式的。c++有一整套不同的铸造风格。
#23
7
I prefer to do the cast, but not manually. My favorite is using g_new
and g_new0
macros from glib. If glib is not used, I would add similar macros. Those macros reduce code duplication without compromising type safety. If you get the type wrong, you would get an implicit cast between non-void pointers, which would cause a warning (error in C++). If you forget to include the header that defines g_new
and g_new0
, you would get an error. g_new
and g_new0
both take the same arguments, unlike malloc
that takes fewer arguments than calloc
. Just add 0
to get zero-initialized memory. The code can be compiled with a C++ compiler without changes.
我喜欢做石膏模型,但不是手工的。我最喜欢使用glib中的g_new和g_new0宏。如果不使用glib,我将添加类似的宏。这些宏在减少代码重复的同时不会降低类型安全性。如果类型错误,则会在非空指针之间产生隐式转换,这会导致警告(c++中的错误)。如果忘记包含定义g_new和g_new0的头,则会出现错误。g_new和g_new0都接受相同的参数,不像malloc,它比calloc接受更少的参数。只要添加0就可以获得零初始化内存。可以使用c++编译器编译代码,不需要修改。
#24
4
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.
空指针是一个通用指针,C支持隐式转换,从空指针类型到其他类型,因此不需要显式地将它进行类型转换。
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++平台上完全兼容相同的代码,那么您需要进行类型转换,因此这完全取决于可用性。
#25
4
-
As other stated, it is not needed for C, but for C++.
如前所述,它不是C所需要的,而是c++所需要的。
-
Including the cast may allow a C program or function to compile as C++.
包括强制转换可以允许C程序或函数以c++的形式编译。
-
In C it is unnecessary, as void * is automatically and safely promoted to any other pointer type.
在C中,这是不必要的,因为void *被自动安全地提升到任何其他指针类型。
-
But if you cast then, it can hide an error if you forgot to include stdlib.h. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code).
但是如果您在那时强制转换,如果您忘记包含stdlib.h,它可以隐藏一个错误。这可能会导致崩溃(或者更糟的是,在代码的某些完全不同的部分,直到稍后才会导致崩溃)。
Because stdlib.h contains the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assumes malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug.
因为stdlib。h包含malloc的原型被发现。在没有malloc原型的情况下,标准要求C编译器假设malloc返回一个int,如果没有cast,则在将该整数分配给指针时发出警告;但是,对于cast,这个警告并没有产生,隐藏了一个bug。
#26
2
The casting of malloc is unnecessary in C but mandatory in C++.
malloc在C中是不必要的,但是在c++中是必须的。
- Casting is unnecessary in C because of void * is automatically and safely promoted to any other pointer type in this case.
- 在C中,由于void *被自动和安全地提升到任何其他指针类型,所以在C中进行转换是不必要的。
- 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.
- 如果指针和整数的大小不同,那么您将通过强制转换来隐藏警告,并可能丢失返回地址的部分。
#27
-4
Please do yourself a favor and more importantly a favor for the next person who will maintain your code, and provide as much information as possible about the data type of a program's variables.
请帮自己一个忙,更重要的是帮下一个维护你代码的人,提供尽可能多的关于程序变量数据类型的信息。
Thus, cast
the returned pointer from malloc
. In the following code the compiler can be assured that sieve is in fact being assigned a point to an integer(s).
因此,从malloc中释放返回的指针。在下面的代码中,编译器可以确保筛子实际上被分配给一个整数点。
int *sieve = (int *) malloc(sizeof(int) * length);
This reduces the chance for a human error when/if the data type for sieve is changed.
这减少了在更改筛网的数据类型时发生人为错误的可能性。
I would be interested in knowing if there are any "pure" C compilers that would flag this statement as being in error. If so, let me know, so that I can avoid them as their lack of type checking will increase the overall expense of maintaining software.
我感兴趣的是知道是否有“纯”C编译器将此语句标记为错误。如果是这样,请让我知道,这样我就可以避免它们,因为它们缺少类型检查将增加维护软件的总体开销。
#1
1886
No; you don't cast the result, since:
没有;你没有预测结果,因为:
- It is unnecessary, as
void *
is automatically and safely promoted to any other pointer type in this case. - 这是不必要的,因为在这种情况下,void *会自动安全地升级到任何其他指针类型。
- It adds clutter to the code, casts are not very easy to read (especially if the pointer type is long).
- 它给代码增加了混乱,强制类型转换不太容易读(特别是当指针类型很长时)。
- It makes you repeat yourself, which is generally bad.
- 它会让你重复你自己,这通常是不好的。
- It can hide an error if you forgot to include
<stdlib.h>
. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code). Consider what happens if pointers and integers are differently sized; then you're hiding a warning by casting and might lose bits of your returned address. Note: as of C11 implicit functions are gone from C, and this point is no longer relevant since there's no automatic assumption that undeclared functions returnint
. -
如果忘记包含
,则可以隐藏错误。这可能导致崩溃(或者更糟的是,直到稍后在代码的某些完全不同的部分发生崩溃时才导致崩溃)。考虑如果指针和整数大小不同会发生什么;然后,您通过强制转换来隐藏警告,并可能丢失返回的地址。注意:对于C11隐函数,这一点不再相关,因为没有自动假设未声明的函数返回int。
As a clarification, note that I said "you don't cast", not "you don't need to cast". In my opinion, it's a failure to include the cast, even if you got it right. There are simply no benefits to doing it, but a bunch of potential risks, and including the cast indicates that you don't know about the risks.
澄清一下,注意我说过“你不需要演员”,而不是“你不需要演员”。在我看来,即使你选对了演员阵容,这也是个失败。这样做没有什么好处,但是有很多潜在的风险,包括演员阵容表明你不知道这些风险。
Also note, as commentators point out, that the above talks about straight C, not C++. I very firmly believe in C and C++ as separate languages.
还请注意,正如评论员指出的,上面提到的是直接的C,而不是c++。我非常坚定地相信C和c++是独立的语言。
To add further, your code needlessly repeats the type information (int
) which can cause errors. It's better to dereference the pointer being used to store the return value, to "lock" the two together:
要进一步添加,您的代码不必要地重复可能导致错误的类型信息(int)。最好是取消用于存储返回值的指针,将两者“锁定”在一起:
int *sieve = malloc(length * sizeof *sieve);
This also moves the length
to the front for increased visibility, and drops the redundant parentheses with sizeof
; they are only needed when the argument is a type name. Many people seem to not know (or ignore) this, which makes their code more verbose. Remember: sizeof
is not a function! :)
这也将长度移到前面,以增加可见性,并删除带有sizeof的冗余括号;只有当参数是类型名时才需要它们。许多人似乎不知道(或忽略)这一点,这使得他们的代码更加冗长。记住:sizeof不是一个函数!:)
While moving length
to the front may increase visibility in some rare cases, one should also pay attention that in the general case, it should be better to write the expression as:
虽然在一些罕见的情况下,将长度移动到前面可能会增加可见性,但也要注意,在一般情况下,最好将表达式写成:
int *sieve = malloc(sizeof *sieve * length);
Since keeping the sizeof
first, in this case, ensures multiplication is done with at least size_t
math.
由于首先保持sizeof,在本例中,确保乘法至少使用size_t数学完成。
Compare: malloc(sizeof *sieve * length * width)
vs. malloc(length * width * sizeof *sieve)
the second may overflow the length * width
when width
and length
are smaller types than size_t
.
比较:malloc(sizeof *sieve * length * width)与malloc(length * width * sizeof *筛子)当宽度和长度小于size_t时,第二个可能会溢出length * width。
#2
315
In C, you don't need to cast the return value of malloc
. The pointer to void returned by malloc
is automagically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed. A preferred alternative among the community is to use the following:
在C中,不需要强制转换malloc的返回值。malloc返回的空指针自动转换为正确的类型。但是,如果您希望您的代码使用c++编译器进行编译,则需要强制转换。社区中比较可取的一种选择是使用下列方法:
int *sieve = malloc(sizeof *sieve * length);
which additionally frees you from having to worry about changing the right-hand side of the expression if ever you change the type of sieve
.
另外,如果您改变了筛子的类型,您就不必担心表达式的右边。
Casts are bad, as people have pointed out. Specially pointer casts.
正如人们所指出的,演员阵容很糟糕。特别是指针类型强制转换。
#3
281
You do cast, because:
你做演员,因为:
- It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions).
- 它使您的代码在C和c++之间更具可移植性,正如经验所显示的,许多程序员声称,当他们真正使用c++(或c++本地编译器扩展)编写代码时,他们使用的是C语言。
- Failing to do so can hide an error: note all the SO examples of confusing when to write
type *
versustype **
. - 如果不这样做,就会隐藏一个错误:注意所有的例子,比如在写类型*和类型**时混淆。
- The idea that it keeps you from noticing you failed to
#include
an appropriate header file misses the forest for the trees. It's the same as saying "don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes -- that pesky stdlib.h is the REAL important thing to remember!" - 它阻止你注意到你失败了的想法包括一个适当的头文件忽略了森林的树木。这就好比说“不要担心你没能让编译器抱怨没有看到原型——那个讨厌的stdlib。”h是需要记住的最重要的东西!
- It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that
malloc()
bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs. - 它迫使人们进行额外的认知交叉检查。它将(所谓的)期望类型放在您对该变量的原始大小所做的算术旁边。我敢打赌,您可以做一个SO研究,表明malloc() bug在有cast时被捕获得更快。与断言一样,揭示意图的注释可以减少bug。
- Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago.
- 用一种机器可以检查的方式重复你自己通常是个好主意。事实上,这就是断言,而使用cast就是断言。断言仍然是我们获得代码正确的最通用的技术,因为图灵在很多年以前就提出了这个想法。
#4
142
As other stated, it is not needed for C, but for C++. If you think you are going to compile your C code with a C++ compiler, for which reasons ever, you can use a macro instead, like:
如前所述,它不是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
That way you can still write it in a very compact way:
这样你仍然可以把它写得很紧凑:
int *sieve = NEW(int, 1);
and it will compile for C and C++.
它将编译为C和c++。
#5
92
In C you can implicitly convert a void pointer to any other kind of pointer, so a cast is not necessary. Using one may suggest to the casual observer that there is some reason why one is needed, which may be misleading.
在C语言中,可以隐式地将空指针转换为任何其他类型的指针,因此不需要强制转换。使用其中一种可能会向一般的观察者暗示,有一些原因需要使用它,这可能会产生误导。
#6
89
From the Wikipedia
从*
Advantages to casting
优势,铸造
Including the cast may allow a C program or function to compile as C++.
包括强制转换可以允许C程序或函数以c++的形式编译。
The cast allows for pre-1989 versions of malloc that originally returned a char *.
演员允许在1989年以前的malloc版本中返回一个char *。
Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the malloc() call (although modern compilers and static analyzers can warn on such behaviour without requiring the cast).
如果目标指针类型改变,强制转换可以帮助开发人员识别类型大小的不一致性,特别是当指针被声明在远离malloc()调用的地方时(尽管现代编译器和静态分析器可以在不需要强制转换的情况下对这种行为发出警告)。
Disadvantages to casting
缺点铸造
Under the ANSI C standard, the cast is redundant.
在ANSI C标准下,铸件是多余的。
Adding the cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assume malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug. On certain architectures and data models (such as LP64 on 64-bit systems, where long and pointers are 64-bit and int is 32-bit), this error can actually result in undefined behaviour, as the implicitly declared malloc returns a 32-bit value whereas the actually defined function returns a 64-bit value. Depending on calling conventions and memory layout, this may result in stack smashing. This issue is less likely to go unnoticed in modern compilers, as they uniformly produce warnings that an undeclared function has been used, so a warning will still appear. For example, GCC's default behaviour is to show a warning that reads "incompatible implicit declaration of built-in function" regardless of whether the cast is present or not.
添加强制转换可能会掩盖包含头stdlib的失败。在其中发现了malloc的原型。在没有malloc原型的情况下,标准要求C编译器假设malloc返回一个int,如果没有类型转换,则在将这个整数分配给指针时发出警告;但是,在cast中,这个警告没有产生,隐藏了一个bug。在某些体系结构和数据模型(比如64位系统上的LP64,在那里,long和指针是64位的,而int是32位的),这个错误实际上会导致未定义的行为,因为隐式声明的malloc返回一个32位的值,而实际定义的函数返回64位值。根据调用约定和内存布局,这可能导致堆栈崩溃。在现代编译器中,这个问题不太可能被忽略,因为它们一致地产生警告,表示使用了未声明的函数,因此仍然会出现警告。例如,GCC的默认行为是显示一个警告,该警告的内容是“不兼容的内置函数的隐式声明”,而不管转换是否存在。
If the type of the pointer is changed at its declaration, one may also, need to change all lines where malloc is called and cast.
如果指针的类型在其声明时发生了更改,您也可能需要更改调用malloc并强制转换的所有行。
Although malloc without casting is preferred method and most experienced programmers choose it, you should use whichever you like having aware of the issues.
尽管malloc不强制转换是首选方法,并且大多数经验丰富的程序员都选择它,但是您应该使用您喜欢的任何方法来了解这些问题。
i.e: If you need to compile C program as C++(Although those are separate language) you should use malloc
with casting.
我。e:如果你需要把C程序编译成c++(虽然它们是独立的语言),你应该使用malloc和cast。
#7
81
You don't cast the result of malloc, because doing so adds pointless clutter to your code.
您不会对malloc的结果进行强制转换,因为这样做会给您的代码增加毫无意义的混乱。
The most common reason why people cast the result of malloc is because they are unsure about how the C language works. That's a warning sign: if you don't know how a particular language mechanism works, then don't take a guess. Look it up or ask on Stack Overflow.
人们之所以选择malloc的结果,最常见的原因是他们不确定C语言是如何工作的。这是一个警告信号:如果你不知道一种特定的语言机制是如何工作的,那么不要去猜测。查找或询问堆栈溢出。
Some comments:
一些评论:
-
A void pointer can be converted to/from any other pointer type without an explicit cast (C11 6.3.2.3 and 6.5.16.1).
空指针可以转换为/from任何其他指针类型,而无需显式转换(C11 6.3.2.3和6.5.16.1)。
-
C++ will however not allow an implicit cast between
void*
and another pointer type. So in C++, the cast would have been correct. But if you program in C++, you should usenew
and not malloc(). And you should never compile C code using a C++ compiler.但是c++不允许在void*和另一个指针类型之间进行隐式转换。所以在c++中,cast是正确的。但是如果使用c++编程,应该使用new而不是malloc()。而且您永远不应该使用c++编译器编译C代码。
If you need to support both C and C++ with the same source code, use compiler switches to mark the differences. Do not attempt to sate both language standards with the same code, because they are not compatible.
如果需要使用相同的源代码同时支持C和c++,可以使用编译器开关来标记差异。不要试图用相同的代码来满足这两种语言标准,因为它们不兼容。
-
If a C compiler cannot find a function because you forgot to include the header, you will get a compiler/linker error about that. So if you forgot to include
<stdlib.h>
that's no biggie, you won't be able to build your program.如果一个C编译器不能找到一个函数,因为您忘记包含header,那么您将得到一个编译器/链接器错误。因此,如果您忘记包含
。这没什么大不了的,你不能建立你的程序。 -
On ancient compilers that follow a version of the standard which is more than 25 years old, forgetting to include
<stdlib.h>
would result in dangerous behavior. Because in that ancient standard, functions without a visible prototype implicitly converted the return type toint
. Casting the result from malloc explicitly would then hide away this bug.在遵循标准版本(该标准已有25年以上的历史)的古代编译器上,忘记包含
会导致危险的行为。因为在那个古老的标准中,没有可见原型的函数隐式地将返回类型转换为int类型。 。h>But that is really a non-issue. You aren't using a 25 years old computer, so why would you use a 25 years old compiler?
但这真的是一个无关紧要的问题。你不是在使用一台25岁的电脑,那你为什么要使用一台25岁的编译器呢?
#8
80
In C you get an implicit conversion from void*
to any other (data) pointer.
在C中,您将得到从void*到任何其他(数据)指针的隐式转换。
#9
60
Casting the value returned by malloc()
is not necessary now, but I'd like to add one point that seems no one has pointed out:
现在不需要对malloc()返回的值进行强制转换,但我想补充一点,似乎没有人指出:
In the ancient days, that is, before ANSI C provides the void *
as the generic type of pointers, char *
is the type for such usage. In that case, the cast can shut down the compiler warnings.
在古代,也就是说,在ANSI C提供void *作为指针的泛型类型之前,char *是这种用法的类型。在这种情况下,强制转换可以关闭编译器警告。
Reference: C FAQ
参考:C常见问题解答
#10
46
It is not mandatory to cast the results of malloc
, since it returns void*
, and a void*
can be pointed to any datatype.
由于malloc返回void*,并且void*可以指向任何数据类型,所以不强制强制强制转换malloc的结果。
#11
42
Just adding my experience, studying computer engineering I see that the two or three professors that I have seen writing in C always cast malloc, however the one I asked (with an immense CV and understanding of C) told me that it is absolutely unnecessary but only used to be absolutely specific, and to get the students into the mentality of being absolutely specific. Essentially casting will not change anything in how it works, it does exactly what it says, allocates memory, and casting does not effect it, you get the same memory, and even if you cast it to something else by mistake (and somehow evade compiler errors) C will access it the same way.
只是增加我的经验,学习计算机工程我看到两个或三个教授,我看到写在C总是malloc,然而我问(一个巨大的简历和理解C)告诉我,这是完全不必要的,但只有曾经是绝对明确,并得到学生的心态绝对是特定的。本质上铸造不会改变任何东西在它是如何工作的,它就是它说,内存分配,和铸造并不影响它,你得到同样的记忆,即使你丢给别的误(和某种程度上逃避编译器错误)C将以相同的方式访问它。
Edit: Casting has a certain point. When you use array notation, the code generated has to know how many memory places it has to advance to reach the beginning of the next element, this is achieved through casting. This way you know that for a double you go 8 bytes ahead while for an int you go 4, and so on. Thus it has no effect if you use pointer notation, in array notation it becomes necessary.
编辑:选角有一定的意义。当您使用数组符号时,生成的代码必须知道需要提前多少内存空间才能到达下一个元素的开头,这是通过转换实现的。这样你就知道,对于一个双字节你要前进8个字节而对于一个整数你要前进4个字节,以此类推。因此,如果使用指针表示法,它没有任何影响,在数组表示法中,它是必要的。
#12
27
The returned type is void*, which can be cast to the desired type of data pointer in order to be dereferenceable.
返回的类型为void*,可以将其转换为所需的数据指针类型,以便可以解除引用。
#13
24
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.
空指针是一个通用指针,C支持隐式转换,从空指针类型到其他类型,因此不需要显式地将它进行类型转换。
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++平台上完全兼容相同的代码,那么您需要进行类型转换,因此这完全取决于可用性。
#14
23
Adding to all the information here; this is what The GNU C Library Reference manual says:
添加到这里的所有信息;以下是GNU C库参考手册的内容:
You can store the result of
malloc
into any pointer variable without a cast, because ISO C automatically converts the typevoid *
to another type of pointer when necessary. But the cast is necessary in contexts other than assignment operators or if you might want your code to run in traditional C.您可以将malloc的结果存储到任何指针变量中,而不需要强制转换,因为ISO C在必要时自动将类型void *转换为另一种类型的指针。但是,除了赋值运算符,或者您可能希望代码在传统的C语言中运行之外,强制转换是必需的。
And indeed the ISO C11 standard (p347) says so:
事实上,ISO C11标准(p347)是这样说的:
The pointer returned if the allocation succeeds is suitably aligned so that it may be assigned to a pointer to any type of object with a fundamental alignment requirement and then used to access such an object or an array of such objects in the space allocated (until the space is explicitly deallocated)
如果分配成功返回的指针是适当对齐,这样它可以分配给一个指针指向任何类型的对象与一个基本定位要求,然后用来访问这样一个对象或类对象数组分配空间(直到空间显式分配)
#15
21
It depends on the programming language and compiler. If you use malloc
in C there is no need to type cast it, as it will automatically type cast, However if your using C++ then you should type cast because malloc
will return a void*
type.
它取决于编程语言和编译器。如果您在C中使用malloc,则不需要键入cast,因为它将自动键入cast,但是如果您使用c++,那么您应该键入cast,因为malloc将返回一个void*类型。
#16
20
In the C language, a void pointer can be assigned to any pointer, which is why you should not use a type cast. If you want "type safe" allocation, I can recommend the following macro functions, which I always use in my C projects:
在C语言中,空指针可以分配给任何指针,这就是为什么不应该使用类型转换。如果你想要“类型安全”的分配,我可以推荐以下宏函数,我在C项目中经常用到:
#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)
With these in place you can simply say
有了这些,你可以简单地说
NEW_ARRAY(sieve, length);
For non-dynamic arrays, the third must-have function macro is
对于非动态数组,第三个必须拥有的函数宏是
#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])
which makes array loops safer and more convenient:
使阵列环路更安全、更方便:
int i, a[100];
for (i = 0; i < LEN(a); i++) {
...
}
#17
14
Casting is only for C++ not C.In case you are using a C++ compiler you better change it to C compiler.
铸造只适用于c++而非C。如果你使用c++编译器,你最好把它改成C编译器。
#18
11
People used to GCC and Clang are spoiled. It's not all that good out there.
习惯了GCC和Clang的人被宠坏了。外面并不是那么好。
I have been pretty horrified over the years by the staggeringly aged compilers I've been required to use. Often companies and managers adopt an ultra-conservative approach to changing compilers and will not even test if a new compiler ( with better standards compliance and code optimization ) will work in their system. The practical reality for working developers is that when you're coding you need to cover your bases and, unfortunately, casting mallocs is a good habit if you cannot control what compiler may be applied to your code.
多年来,我一直被要求使用的那些过时的编译器所震惊。通常,公司和管理人员在更改编译器时采用一种极端保守的方法,甚至不会测试一个新的编译器(具有更好的标准遵从性和代码优化)是否在他们的系统中工作。工作开发人员的实际情况是,当您编写代码时,您需要覆盖您的基本内容,不幸的是,如果您无法控制将什么编译器应用到您的代码中,那么抛出mallocs是一个好习惯。
I would also suggest that many organizations apply a coding standard of their own and that that should be the method people follow if it is defined. In the absence of explicit guidance I tend to go for most likely to compile everywhere, rather than slavish adherence to a standard.
我还建议许多组织应用自己的编码标准,如果定义了这个标准,人们应该遵循这个标准。在没有明确指导的情况下,我倾向于在任何地方编译,而不是一味地遵循标准。
The argument that it's not necessary under current standards is quite valid. But that argument omits the practicalities of the real world. We do not code in a world ruled exclusively by the standard of the day, but by the practicalities of what I like to call "local management's reality field". And that's bent and twisted more than space time ever was. :-)
认为在目前的标准下没有必要这样做的观点是很有道理的。但这种观点忽略了现实世界的实际情况。在这个世界上,我们并非完全按照当时的标准行事,而是按照我所称的“地方管理的现实领域”的实际情况行事。它的弯曲和扭曲程度超过了时空。:-)
YMMV.
YMMV。
I tend to think of casting malloc as a defensive operation. Not pretty, not perfect, but generally safe. ( Honestly, if you've not included stdlib.h then you've way more problems than casting malloc ! ).
我倾向于认为使用malloc是一种防御手段。不漂亮,不完美,但总的来说是安全的。(老实说,如果你没有包括stdlib的话。h那么你的问题比铸造malloc要多!)
#19
10
I put in the cast simply to show disapproval of the ugly hole in the type system, which allows code such as the following snippet to compile without diagnostics, even though no casts are used to bring about the bad conversion:
我输入强制转换只是为了表示对类型系统中丑陋的漏洞的反对,它允许不使用强制转换来编译如下代码片段,而不使用任何强制转换:
double d;
void *p = &d;
int *q = p;
I wish that didn't exist (and it doesn't in C++) and so I cast. It represents my taste, and my programming politics. I'm not only casting a pointer, but effectively, casting a ballot, and casting out demons of stupidity. If I can't actually cast out stupidity, then at least let me express the wish to do so with a gesture of protest.
我希望它不存在(在c++中也不存在),所以我进行了cast。它代表了我的品味和我的编程政治。我不仅投了一个指示,而且有效地投了一张选票,并赶走了愚蠢的恶魔。如果我不能真正摆脱愚蠢,那么至少让我以*的姿态来表达我的愿望。
In fact, a good practice is to wrap malloc
(and friends) with functions that return unsigned char *
, and basically never to use void *
in your code. If you need a generic pointer-to-any-object, use a char *
or unsigned char *
, and have casts in both directions. The one relaxation that can be indulged, perhaps, is using functions like memset
and memcpy
without casts.
实际上,一个很好的实践是用返回无符号字符*的函数包装malloc(和friends),并且基本上永远不会在代码中使用void *。如果您需要一个通用的指针到任何对象,请使用char *或unsigned char *,并在两个方向上进行强制转换。一个可以放松的方法是使用像memset和memcpy这样的函数而不用强制类型转换。
On the topic of casting and C++ compatibility, if you write your code so that it compiles as both C and C++ (in which case you have to cast the return value of malloc
when assigning it to something other than void *
), you can do a very helpful thing for yourself: you can use macros for casting which translate to C++ style casts when compiling as C++, but reduce to a C cast when compiling as C:
铸造和c++的主题兼容性,如果你写代码,编译C和c++(在这种情况下,你必须把malloc分配时的返回值不是void *),你可以为自己做一个非常有用的事:您可以使用宏来铸造时转化为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
If you adhere to these macros, then a simple grep
search of your code base for these identifiers will show you where all your casts are, so you can review whether any of them are incorrect.
如果您坚持使用这些宏,那么对这些标识符的代码库进行简单的grep搜索将显示所有的类型转换在哪里,以便您可以检查它们是否有错误。
Then, going forward, if you regularly compile the code with C++, it will enforce the use of an appropriate cast. For instance, if you use strip_qual
just to remove a const
or volatile
, but the program changes in such a way that a type conversion is now involved, you will get a diagnostic, and you will have to use a combination of casts to get the desired conversion.
然后,如果您经常使用c++编译代码,那么它将强制使用适当的cast。例如,如果您使用strip_qual来删除一个const或volatile,但是程序会以这样一种方式改变,即现在涉及到类型转换,您将得到一个诊断,您将不得不使用组合的类型转换来获得所需的转换。
To help you adhere to these macros, the the GNU C++ (not C!) compiler has a beautiful feature: an optional diagnostic which is produced for all occurrences of C style casts.
为了帮助您遵循这些宏,GNU 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.
If your C code compiles as C++, you can use this -Wold-style-cast
option to find out all occurrences of the (type)
casting syntax that may creep into the code, and follow up on these diagnostics by replacing it with an appropriate choice from among the above macros (or a combination, if necessary).
如果你的C代码编译为c++,您可以使用此-Wold-style-cast选项来找出(类型)铸件出现的所有语法,可能会潜入代码,并跟进这些诊断,代之以一个适当的选择从上面的宏(或组合,如果有必要的话)。
This treatment of conversions is the single largest standalone technical justification for working in a "Clean C": the combined C and C++ dialect, which in turn technically justifies casting the return value of malloc
.
这种对转换的处理是在“干净的C”中工作的最大的独立技术理由:C和c++方言的结合,这反过来又在技术上证明了使用malloc的返回值是正确的。
#20
9
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
void指针背后的概念是它可以被强制到任何数据类型,这就是malloc返回void的原因。您还必须了解自动排版。所以虽然你必须这样做,但并不一定要强制转换指针。它有助于保持代码的整洁,并有助于调试
#21
8
The best thing to do when programming in C whenever it is possible:
当用C语言编程时,最好的方法是:
- Make your program compile through a C compiler with all warnings turned on
-Wall
and fix all errors and warnings - 让您的程序通过C编译器编译,并在-Wall上打开所有警告,并修复所有错误和警告
- Make sure there are no variables declared as
auto
- 确保没有声明为auto的变量。
- Then compile it using a C++ compiler with
-Wall
and-std=c++11
. Fix all errors and warnings. - 然后使用带有-Wall和-std=c++11的c++编译器进行编译。修正所有的错误和警告。
- Now compile using the C compiler again. Your program should now compile without any warning and contain fewer bugs.
- 现在再次使用C编译器进行编译。您的程序现在应该没有任何警告,并且包含更少的错误。
This procedure lets you take advantage of C++ strict type checking, thus reducing the number of bugs. In particular, this procedure forces you to include stdlib.h
or you will get
这个过程使您可以利用c++严格的类型检查,从而减少错误的数量。特别是,这个过程强制您包含stdlib。贺南洪你会得到
malloc
was not declared within this scopemalloc不在此范围内声明
and also forces you to cast the result of malloc
or you will get
也迫使你投射malloc的结果,否则你会得到
invalid conversion from
void*
toT*
无效转换从void*到T*
or what ever your target type is.
或者你的目标类型是什么。
The only benefits from writing in C instead of C++ I can find are
用C而不是c++写作的唯一好处是
- C has a well specified ABI
- C有一个明确的ABI
- C++ may generate more code [exceptions, RTTI, templates, runtime polymorphism]
- c++可以生成更多的代码[异常,RTTI,模板,运行时多态性]
Notice that the second cons should in the ideal case disappear when using the subset common to C together with the static polymorphic feature.
注意,在理想情况下,当使用C的公共子集以及静态多态特性时,第二个缺点应该会消失。
For those that finds C++ strict rules inconvenient, we can use the C++11 feature with inferred type
对于那些发现c++严格规则不方便的人,我们可以使用带有推断类型的c++ 11特性
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
#22
8
No, you don't cast the result of malloc()
.
In general, you don't cast to or from void *
.
一般来说,您不会对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.
不这样做的一个典型原因是#include
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):
在C语言中,指针强制转换几乎总是一个错误。这是因为以下规则(§6.5 p7 N1570,最新的草案为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.对象只能通过具有以下类型之一的lvalue表达式访问其存储值:——一种兼容的有效类型对象,——一个合格的版本的类型兼容的有效类型对象,——一种符号(或无符号类型对应的有效类型对象,——一种符号(或无符号类型对应一个合格的版本的有效的类型的对象,-一种集合或联合类型,在其成员(递归地包括子集合或包含的联合的成员)中包含上述类型之一,或——字符类型。
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.
简而言之:因为在C语言中,任何指针强制转换的出现都应该引起需要特别注意的代码的注意,所以不应该编写不必要的指针强制转换。
Side notes:
边注:
-
There are cases where you actually need a cast to
void *
, e.g. 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.在这里,cast是必需的,因为printf()是一个可变的函数,所以隐式转换不起作用。
-
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++中,对void *的转换不是隐式的。c++有一整套不同的铸造风格。
#23
7
I prefer to do the cast, but not manually. My favorite is using g_new
and g_new0
macros from glib. If glib is not used, I would add similar macros. Those macros reduce code duplication without compromising type safety. If you get the type wrong, you would get an implicit cast between non-void pointers, which would cause a warning (error in C++). If you forget to include the header that defines g_new
and g_new0
, you would get an error. g_new
and g_new0
both take the same arguments, unlike malloc
that takes fewer arguments than calloc
. Just add 0
to get zero-initialized memory. The code can be compiled with a C++ compiler without changes.
我喜欢做石膏模型,但不是手工的。我最喜欢使用glib中的g_new和g_new0宏。如果不使用glib,我将添加类似的宏。这些宏在减少代码重复的同时不会降低类型安全性。如果类型错误,则会在非空指针之间产生隐式转换,这会导致警告(c++中的错误)。如果忘记包含定义g_new和g_new0的头,则会出现错误。g_new和g_new0都接受相同的参数,不像malloc,它比calloc接受更少的参数。只要添加0就可以获得零初始化内存。可以使用c++编译器编译代码,不需要修改。
#24
4
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.
空指针是一个通用指针,C支持隐式转换,从空指针类型到其他类型,因此不需要显式地将它进行类型转换。
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++平台上完全兼容相同的代码,那么您需要进行类型转换,因此这完全取决于可用性。
#25
4
-
As other stated, it is not needed for C, but for C++.
如前所述,它不是C所需要的,而是c++所需要的。
-
Including the cast may allow a C program or function to compile as C++.
包括强制转换可以允许C程序或函数以c++的形式编译。
-
In C it is unnecessary, as void * is automatically and safely promoted to any other pointer type.
在C中,这是不必要的,因为void *被自动安全地提升到任何其他指针类型。
-
But if you cast then, it can hide an error if you forgot to include stdlib.h. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code).
但是如果您在那时强制转换,如果您忘记包含stdlib.h,它可以隐藏一个错误。这可能会导致崩溃(或者更糟的是,在代码的某些完全不同的部分,直到稍后才会导致崩溃)。
Because stdlib.h contains the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assumes malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug.
因为stdlib。h包含malloc的原型被发现。在没有malloc原型的情况下,标准要求C编译器假设malloc返回一个int,如果没有cast,则在将该整数分配给指针时发出警告;但是,对于cast,这个警告并没有产生,隐藏了一个bug。
#26
2
The casting of malloc is unnecessary in C but mandatory in C++.
malloc在C中是不必要的,但是在c++中是必须的。
- Casting is unnecessary in C because of void * is automatically and safely promoted to any other pointer type in this case.
- 在C中,由于void *被自动和安全地提升到任何其他指针类型,所以在C中进行转换是不必要的。
- 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.
- 如果指针和整数的大小不同,那么您将通过强制转换来隐藏警告,并可能丢失返回地址的部分。
#27
-4
Please do yourself a favor and more importantly a favor for the next person who will maintain your code, and provide as much information as possible about the data type of a program's variables.
请帮自己一个忙,更重要的是帮下一个维护你代码的人,提供尽可能多的关于程序变量数据类型的信息。
Thus, cast
the returned pointer from malloc
. In the following code the compiler can be assured that sieve is in fact being assigned a point to an integer(s).
因此,从malloc中释放返回的指针。在下面的代码中,编译器可以确保筛子实际上被分配给一个整数点。
int *sieve = (int *) malloc(sizeof(int) * length);
This reduces the chance for a human error when/if the data type for sieve is changed.
这减少了在更改筛网的数据类型时发生人为错误的可能性。
I would be interested in knowing if there are any "pure" C compilers that would flag this statement as being in error. If so, let me know, so that I can avoid them as their lack of type checking will increase the overall expense of maintaining software.
我感兴趣的是知道是否有“纯”C编译器将此语句标记为错误。如果是这样,请让我知道,这样我就可以避免它们,因为它们缺少类型检查将增加维护软件的总体开销。