在这个问题,有人建议意见,我应该不会投的结果malloc
,即
int *sieve = malloc(sizeof(int) * length);
而不是:
int *sieve = (int *) malloc(sizeof(int) * length);
为什么会这样呢?
NULL
。(这可能就是C ++引入的原因nullptr
:C ++不允许任何隐式指针强制转换)
在这个问题,有人建议意见,我应该不会投的结果malloc
,即
int *sieve = malloc(sizeof(int) * length);
而不是:
int *sieve = (int *) malloc(sizeof(int) * length);
为什么会这样呢?
NULL
。(这可能就是C ++引入的原因nullptr
:C ++不允许任何隐式指针强制转换)
Answers:
无 ; 您不投放结果,因为:
void *
在这种情况下会自动安全地提升为任何其他指针类型。<stdlib.h>
。这可能会导致崩溃(或者,更糟糕的,没有代码的一些完全不同的部分会导致崩溃,直到后来的方式)。考虑一下如果指针和整数的大小不同会怎样?那么您将通过投射隐藏警告,并且可能会丢失返回地址的一部分。注意:从C99开始,隐式函数已从C删除,这一点不再相关,因为没有自动假定未声明的函数返回int
。为了澄清起见,请注意我说的是“您不要投”,而不是“您不需要投”。我认为,即使您没做错,也不能包括演员表。这样做根本没有任何好处,但是有很多潜在风险,包括强制转换说明您不知道这些风险。
还要注意,正如评论员指出的那样,以上内容是关于直接C而不是C ++的。我非常坚信C和C ++是独立的语言。
要添加更多内容,您的代码无需重复输入类型信息(int
),这可能会导致错误。最好取消引用用于存储返回值的指针,以将两者“锁定”在一起:
int *sieve = malloc(length * sizeof *sieve);
还将移到length
最前面以提高可见性,并用sizeof
;删除多余的括号。他们只需要当参数为类型名称使用。许多人似乎不知道(或忽略)这一点,这会使他们的代码更加冗长。记住:sizeof
不是函数!:)
尽管在某些极少数情况下移到length
最前面可能会增加可见性,但也应注意,在一般情况下,将表达式写为:
int *sieve = malloc(sizeof *sieve * length);
由于保持 sizeof
在这种情况下一个,确保至少用size_t
数学运算即可完成乘法运算。
比较:malloc(sizeof *sieve * length * width)
vs。malloc(length * width * sizeof *sieve)
秒可能溢出length * width
when width
和length
小于类型size_t
。
int x = (int) 12;
只是为了弄清楚事情?
(int)12
也无法比拟。12
是的int
,中投确实根本不算什么。的检索malloc()
是void *
,而不是强制转换为的指针类型。(如果不是void *
,所以比喻(int)12
是(void*)malloc(…)
什么没有人讨论。)
在C中,您无需强制转换的返回值malloc
。返回的指向void的指针malloc
会自动转换为正确的类型。但是,如果希望代码使用C ++编译器进行编译,则需要进行强制转换。社区中首选的替代方法是使用以下方法:
int *sieve = malloc(sizeof *sieve * length);
此外,如果您更改了表达式的类型,这也使您不必担心更改表达式的右侧 sieve
。
正如人们指出的那样,演员表很糟糕。特别是指针转换。
malloc(length * sizeof *sieve)
使它看起来像是sizeof
一个变量-因此我认为malloc(length * sizeof(*sieve))
它更具可读性。
malloc(length * (sizeof *sieve))
更具可读性。恕我直言。
()
问题,请注意,您建议的样式已切换顺序。,考虑元素计数的计算方式如length*width
,sizeof
在这种情况下,请保持第一个数以确保至少用size_t
数学运算完成乘法。比较malloc(sizeof( *ptr) * length * width)
对比 malloc(length * width * sizeof (*ptr))
-第二可能溢出length*width
时,width,length
较小类型size_t
。
malloc(sizeof *sieve * length)
static_cast>()
(或reinterpret_cast<>()
)不与C的任何方言兼容
您进行强制转换是因为:
type *
和编写时会混淆type **
。#include
适当的头文件失败的想法错过了树木的森林。就像说“不要担心您没有要求编译器抱怨没有看到原型的事实-讨厌的stdlib.h是要记住的真正重要的事情!”malloc()
更快地错误。与断言一样,揭示意图的注释会减少错误。.c
/ .cpp
文件进行编译不是很有用,但一种情况是throw
在使用C ++编译器编译时(但return -1;
在使用C编译器编译时或其他方式下)添加C ++ 支持。
malloc
:char **foo = malloc(3*sizeof(*foo));
如果非常充分证明:3个指向char指针的指针。然后循环执行foo[i] = calloc(101, sizeof(*(foo[i])));
。分配101个字符的数组,整齐地初始化为零。不需要演员表。将此声明更改为unsigned char
或其他任何类型,您仍然会很好
struct Zebra *p; ... p=malloc(sizeof struct Zebra);
,malloc不能避免复制有关p的类型的信息,但是如果一种类型改变而另一种类型没有改变,则编译器和本地代码检查都不会检测到任何问题。更改代码为p=(struct Zebra*)malloc(sizeof struct Zebra);
,如果强制转换类型不匹配p
,编译器将发出尖叫声,并且本地检查将显示...
正如其他人所述,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 ++进行编译。
new
C ++的定义中使用宏呢?
new
,你必须使用delete
,如果你使用malloc()
你必须你free()
。切勿混合。
NEW
可能不是一个好主意,因为永远不会使用delete
(或DELETE
)返回资源,因此您要混用词汇表。相反,命名它MALLOC
(或更确切地说CALLOC
在这种情况下)会更有意义。
从维基百科:
铸造的优势
包括强制转换可能允许C程序或函数编译为C ++。
强制转换允许1989年前的malloc版本最初返回char *。
如果目标指针类型发生更改,则强制转换可以帮助开发人员识别类型大小不一致的地方,尤其是如果声明的指针远离malloc()调用时(尽管现代编译器和静态分析器可以在不需要强制转换的情况下警告此类行为)。
铸造的缺点
在ANSI C标准下,强制转换是多余的。
添加强制类型转换可能会掩盖未能包含标头stdlib.h的失败,其中找到了malloc的原型。在没有malloc原型的情况下,该标准要求C编译器假定malloc返回一个int。如果没有强制转换,则在将此整数分配给指针时会发出警告;否则,将发出警告。但是,使用强制转换时,不会产生此警告,从而隐藏了错误。在某些体系结构和数据模型上(例如64位系统上的LP64,其中long和指针是64位,而int是32位),此错误实际上可能导致未定义的行为,因为隐式声明的malloc返回32-位值,而实际定义的函数返回64位值。根据调用约定和内存布局,这可能会导致堆栈崩溃。这个问题在现代编译器中不太可能被忽视,由于它们会统一发出警告,提示已使用未声明的功能,因此仍会出现警告。例如,GCC的默认行为是显示一条警告,显示“内置函数的不兼容隐式声明”,无论是否存在强制转换。
如果指针的类型在其声明处更改,则可能还需要更改调用malloc并强制转换的所有行。
尽管不进行强制转换的malloc是首选方法,并且大多数有经验的程序员都选择它,但是您应该使用任何了解问题的方法。
即:如果需要将C程序编译为C ++(尽管它是一种独立的语言),则必须强制转换use的结果malloc
。
malloc()
调用,则“ 强制转换可以帮助开发人员识别类型大小不一致 ”是什么意思?你能举个例子吗?
p = malloc(sizeof(*p) * count)
习惯用法会自动获取类型中的更改,因此您不必获得警告就可以进行任何更改。因此,与非广播的最佳选择相比,这并不是真正的优势。
您不会转换malloc的结果,因为这样做会给您的代码增加毫无意义的混乱。
人们使用malloc结果的最常见原因是因为他们不确定C语言的工作方式。这是一个警告信号:如果您不知道特定语言机制的工作原理,那就不要猜测。查找它或询问堆栈溢出。
一些评论:
无需显式强制转换即可将空指针转换为任何其他指针类型或从任何其他指针类型转换为空指针(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年历史的编译器呢?
在C语言中,您将获得从void *
到任何其他(数据)指针的隐式转换。
投射由返回的值 malloc()
现在不需要,但是我想补充一点,似乎没有人指出:
在古代,也就是在ANSI C提供void *
指针作为通用类型之前,char *
就是这种用法的类型。在这种情况下,强制转换可以关闭编译器警告。
参考:C常见问题解答
只是加我的经验,研究计算机工程,我发现我看到用C语言编写的两三位教授总是会转换malloc,但是我问的一位教授(具有丰富的CV和对C的理解)告诉我,这绝对是不必要的,但仅过去是绝对特定的,并且使学生陷入绝对特定的心态。本质上,强制转换不会改变其工作方式,它会完全按照其说的那样进行操作,分配内存,并且强制转换不会影响它,您将获得相同的内存,即使您错误地将其强制转换为其他内容(并以某种方式逃避了编译器)错误),C将以相同的方式访问它。
编辑:铸造有一定意义。使用数组表示法时,生成的代码必须知道要到达下一个元素的开头要前进多少个内存位置,这是通过强制转换实现的。这样一来,您就知道对于双精度而言,您要提前8个字节,而对于int而言,您要提前4个字节,依此类推。因此,如果使用指针表示法则没有效果,而在数组表示法中则很有必要。
p = malloc(sizeof *p * n);
是如此简单且更好。
void指针是通用对象指针,C支持从void指针类型到其他类型的隐式转换,因此无需显式类型转换。
但是,如果您希望同一代码在不支持隐式转换的C ++平台上完全兼容,则需要进行类型转换,因此这完全取决于可用性。
malloc
在C ++中使用和朋友是一个很好的警告信号,它值得特别注意(或用C重新编写)。
void *
,因此void *
不足以很好地存储函数指针。
这就是《 GNU C库参考》手册所说的内容:
您可以将结果存储
malloc
到任何指针变量中而无需强制转换,因为ISO Cvoid *
在必要时会自动将类型转换为另一种指针类型。但是,在除赋值运算符之外的其他上下文中,或者如果您希望代码在传统C语言中运行,则强制转换是必需的。
实际上,ISO C11标准(p347)表示:
如果分配成功,则返回的指针将进行适当对齐,以便可以将其分配给具有基本对齐要求的任何类型的对象的指针,然后将其用于访问分配的空间中的此类对象或此类对象的数组(直到空间已明确释放)
返回的类型为void *,可以将其强制转换为所需的数据指针类型,以便将其取消引用。
void*
可以强制转换为所需的类型,但无需这样做,因为它将被自动转换。因此,强制转换不是必需的,而实际上由于高分答案中提到的原因是不希望的。
在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++) {
...
}
malloc()
。
void*
在这些情况下,向函数指针分配或从函数指针分配可能会丢失信息,因此“可以将空指针分配给任何指针”是一个问题。但是,将void*
from 分配malloc()
给任何对象指针都不是问题。
do
与涉及循环尚未宏想知道从标题的问题走循环评论。删除该评论。以后也将这个拆下来。
习惯了GCC和Clang的人都被宠坏了。那里不是很好。
多年来,我一直被要求使用的陈旧的编译器吓坏了。公司和经理经常采用超保守的方法来更改编译器,甚至不会测试是否有新的编译器(具有更好的标准合规性和代码优化功能)可以在其系统中工作。对于正在工作的开发人员来说,实际的现实情况是,在编写代码时,您需要覆盖基础知识,并且不幸的是,如果无法控制将哪种编译器应用于代码,则强制转换malloc是一个好习惯。
我还建议许多组织采用自己的编码标准, ,应该是如果它被定义的方法的人跟随。在没有明确指导的情况下,我倾向于最有可能在任何地方进行编译,而不是刻意遵守标准。
在当前的标准下没有必要的论点是正确的。但是,这种说法忽略了现实世界的实用性。我们不是在一个完全由当今的标准统治的世界中进行编码,而是在我喜欢称之为“本地管理的现实领域”的实用性方面。而且这种弯曲和扭曲比空时更是如此。:-)
YMMV。
我倾向于将malloc转换为一种防御性操作。不漂亮,不完美,但总体上是安全的。(老实说,如果你不包含stdlib.h中那么你的方式比铸造的malloc更多的问题!)。
我只是为了表示不赞成使用类型系统中的丑陋漏洞而使用了强制类型转换,即使没有使用强制类型转换导致不良转换,该类型系统也允许以下代码段的代码无需诊断即可编译:
double d;
void *p = &d;
int *q = p;
我希望它不存在(并且在C ++中不存在),所以我进行了转换。它代表了我的品味和我的编程政治。我不仅在投下指针,而且在有效地投下选票,并投出愚蠢的恶魔。如果我不能真正 消除愚蠢,那么至少让我表达抗议的意愿。
实际上,一个好的做法是malloc
使用return的函数包装(和朋友)unsigned char *
,并且基本上不要void *
在您的代码中使用它们。如果需要通用的指向任何对象的指针,请使用char *
或unsigned char *
,并进行双向转换。可以放纵的一种放松可能是使用类似memset
和memcpy
不使用强制转换的功能。
关于强制转换和C ++兼容性这一主题,如果您编写代码以使其同时作为C和C ++进行编译(在这种情况下,当您将其赋值给除以外的其他值时,您必须强制转换返回值),那么您可以做一个非常有帮助的工作自己做一件事:您可以使用宏进行转换,当转换为C ++时可以转换为C ++样式转换,但是当转换为C时可以转换为C转换:malloc
void *
/* 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
仅用于删除const
或volatile
,但是程序更改的方式使得现在涉及类型转换,则将得到诊断,并且必须使用强制类型转换的组合来获得所需的转换。
为了帮助您坚持使用这些宏,GNU C ++(不是C!)编译器具有一个漂亮的功能:针对所有C样式强制转换生成的可选诊断程序。
-Wold-style-cast(仅C ++和Objective-C ++) 如果使用旧样式(C样式)强制转换为非无效类型,则发出警告 在C ++程序中。新型的类型转换(dynamic_cast, static_cast,reinterpret_cast和const_cast)的脆弱性较小 产生意想不到的效果,并且更容易搜索。
如果您的C代码编译为C ++,则可以使用此-Wold-style-cast
选项找出(type)
可能会渗入到代码中的所有强制转换语法,并通过在上述宏(或组合(如果需要)。
转换的处理是在“ Clean C”中工作的最大的独立技术理由:C和C ++的组合方言,这又在技术上证明了转换C的返回值是合理的malloc
。
尽可能在C中进行编程时最好的做法:
-Wall
并修复所有错误和警告auto
-Wall
和的C ++编译器进行编译-std=c++11
。修复所有错误和警告。此过程使您可以利用C ++严格类型检查,从而减少错误的数量。特别是,此过程会迫使您加入,stdlib.h
否则您将获得
malloc
未在此范围内声明
并迫使您投放的结果,malloc
否则您将获得
从转换
void*
为T*
或您的目标类型是什么。
我可以找到用C而不是C ++编写的唯一好处是
请注意,在理想情况下,将C共有的子集与静态多态特征一起使用时,第二个缺点应该消失。
对于那些觉得C ++严格规则不方便的人,我们可以将C ++ 11功能与推断类型一起使用
auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...
gcc -c c_code.c
),将C ++代码编译为C ++(例如g++ -c cpp_code.cpp
),然后将它们链接在一起(例如gcc c_code.o cpp_code.o
,反之亦然,取决于项目依赖性)。现在应该没有理由剥夺任何一种语言的任何出色功能了……
p = malloc(sizeof(*p));
,如果p
更改为其他类型名称,则无需首先更改。提议的强制转换的“优势”是,如果p
类型错误,则会出现编译错误,但如果“ Just Works”会更好。
malloc()
。通常,您不会向或从进行强制转换void *
。
不这样做的一个典型原因是失败#include <stdlib.h>
可能会被忽略。由于C99将隐式函数声明定为非法,因此现在不再是一个问题,因此,如果您的编译器至少符合C99,您将收到诊断消息。
但是有一个更强烈的理由不引入不必要的指针强制转换:
在C语言中,指针强制转换几乎总是错误。这是由于以下规则(N1570中的第6.5节p7,C11的最新草案):
一个对象只能通过具有以下类型之一的左值表达式访问其存储值:
—与对象的有效类型兼容的类型,
— 与对象的有效类型兼容的类型的限定版本,
—类型是与对象的有效类型相对应的有符号或无符号类型,
- 与对象的有效类型的合格版本相对应的有符号或无符号类型的类型,
-包括一个在其成员之间(包括递归地包括一个子集合或所包含的并集的成员)中的上述类型,或
-字符类型。
这也称为严格别名规则。所以下面的代码是未定义的行为:
long x = 5;
double *p = (double *)&x;
double y = *p;
而且,有时还令人惊讶的是:
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;
有时,您确实需要强制转换指针,但是鉴于严格的别名规则,您必须非常小心。因此,任何在代码中强制转换指针的情况都是您必须仔细检查其有效性的地方。因此,您永远不会编写不必要的指针强制转换。
一言以蔽之:因为在C,任何一个发生指针投应提高对需要特别注意的代码红旗,你永远不应该写不必要的指针类型转换。
旁注:
在某些情况下,您实际上需要强制转换为void *
,例如,如果要打印指针:
int x = 5;
printf("%p\n", (void *)&x);
在这里printf()
强制转换是必需的,因为它是可变函数,所以隐式转换不起作用。
在C ++中,情况有所不同。在处理派生类的对象时,强制转换指针类型有些普遍(并且正确)。因此,是非常有意义的在C ++中,转换和从void *
是不隐式的。C ++具有一整套不同的铸造风格。
仅针对C ++而不是C进行强制转换。如果您使用的是C ++编译器,则最好将其更改为C编译器。
void指针背后的概念是可以将其强制转换为任何数据类型,这就是malloc返回void的原因。另外,您必须注意自动类型转换。因此,尽管必须执行强制转换,但这不是强制性的。它有助于保持代码的清洁并有助于调试
空指针是通用指针,C支持从空指针类型到其他类型的隐式转换,因此无需显式类型转换。
但是,如果您希望同一代码在不支持隐式转换的C ++平台上完全兼容,则需要进行类型转换,因此这完全取决于可用性。
如前所述,C不需要,但C ++不需要。
包括强制转换可能允许C程序或函数编译为C ++。
在C语言中,这是不必要的,因为void *将自动安全地提升为任何其他指针类型。
但是,如果您进行强制转换,那么如果忘记包括stdlib.h,它可能会隐藏错误 。这可能会导致崩溃(或更糟糕的是,直到稍后在代码的某些完全不同的部分中才导致崩溃)。
因为stdlib.h包含找到malloc的原型。在没有malloc原型的情况下,该标准要求C编译器假定malloc返回一个int。如果没有强制转换,则在将此整数分配给指针时会发出警告;否则,将发出警告。但是,使用强制转换时,不会产生此警告,从而隐藏了错误。