我在这个帖子上对我的回答发表了评论:

函数调用中的Malloc似乎在返回时被释放?

简而言之,我有这样的代码:

int * somefunc (void)
{
  int * temp = (int*) malloc (sizeof (int));
  temp[0] = 0;
  return temp;
}

我收到了这条评论:

  

我可以说,请不要施放   malloc的返回值?它不是   需要并且可以隐藏错误。

我同意在C中不需要强制转换。它在C ++中是强制性的,所以我通常添加它们以防万一我必须在一天内用C ++移植代码。

但是,我想知道这样的演员是如何隐藏错误的。有什么想法吗?

编辑:

似乎双方都有非常好的和有效的论据。感谢发帖,伙计们。

有帮助吗?

解决方案

我发布答案似乎很合适,因为我留下了评论:P

基本上,如果您忘记包含stdlib.h,编译器将假设malloc返回int。没有施法,你会收到警告。铸造你不会。

因此,通过施放你什么也得不到,并冒着压制合法警告的风险。

关于这一点的文章很多,快速的谷歌搜索会提供更详细的解释。

修改

有人认为

TYPE * p;
p = (TYPE *)malloc(n*sizeof(TYPE));

当你意外地没有分配足够的内存时显而易见,因为你认为p TYPe TYPE p = malloc(sizeof(*p)*n); <=> <=>,因此我们应该使用malloc,因为这种方法的优点是覆盖了意外的较小成本抑制编译器警告。

我想指出两件事:

  1. 你应该写<=>总是确保你有足够的空间
  2. 使用上述方法,如果您更改了<=>的类型,则需要在3个位置进行更改:一次在声明中,一次在<=>中,一次在演员表中。
  3. 简而言之,我个人认为没有必要投出<=>的返回值,这当然不是最佳做法。

其他提示

这个问题被标记为C和C ++,所以它至少有两个答案,恕我直言:

C

唉......做你想做的事。

我相信上面给出的原因<!>“如果你不包含<!>”; stdlib <!>然后你就不会收到警告<!>不是有效的,因为不应该依赖这种黑客来忘记包含标题。

可能让你编写演员表的真正原因是C编译器已经默默地将void *转换为你想要的任何指针类型,因此,自己动手做是有点过分和无用的

如果你想要类型安全,你可以切换到C ++或编写自己的包装函数,如:

int * malloc_Int(size_t p_iSize) /* number of ints wanted */
{
   return malloc(sizeof(int) * p_iSize) ;
}

C ++

有时,即使在C ++中,您也必须从malloc / realloc / free utils中获利。然后你将不得不施展。但你已经知道了。使用static_cast <!> lt; <!> gt;()将一如既往地比C风格的强制转换更好。

在C中,您可以通过模板覆盖malloc(和realloc等)以实现类型安全:

template <typename T>
T * myMalloc(const size_t p_iSize)
{
 return static_cast<T *>(malloc(sizeof(T) * p_iSize)) ;
}

将使用如下:

int * p = myMalloc<int>(25) ;
free(p) ;

MyStruct * p2 = myMalloc<MyStruct>(12) ;
free(p2) ;

和以下代码:

// error: cannot convert ‘int*’ to ‘short int*’ in initialization
short * p = myMalloc<int>(25) ;
free(p) ;

不会编译,因此,没有问题

总而言之,在纯C ++中,如果有人在你的代码中找到多个C malloc,你现在没有任何借口...... : - )

C + C ++交叉

有时,您希望生成可以在C和C ++中编译的代码(无论出于何种原因......这不是C ++ extern "C" {}块的重点吗?)。在这种情况下,C ++需要强制转换,但C不会理解static_cast关键字,因此解决方案是C风格的强制转换(由于这种原因,它在C ++中仍然是合法的。)

请注意,即使编写纯C代码,使用C ++编译器编译它也会获得更多警告和错误(例如,尝试使用函数而不首先声明它将无法编译,这与上面提到的错误不同)

因此,为了安全起见,编写将在C ++中干净地编译的代码,研究并更正警告,然后使用C编译器生成最终的二进制文件。这意味着再次以C风格的演员阵容写出演员阵容。

如果您使用C(而不是C ++)在64位系统上进行编译,则可能引入的一个错误。

基本上,如果您忘记包含stdlib.h,则将应用默认的int规则。因此,编译器会愉快地假设malloc具有int malloc();原型的许多64位系统,int为32位,指针为64位。

哦,这个值被截断了,你只得到了指针的低32位!现在,如果您转换<=>的返回值,则此错误将被强制转换隐藏。但如果你不这样做,你会得到一个错误(<!>的性质的东西;不能将int转换为T * <!>“;)。

这当然不适用于C ++有两个原因。首先,它没有默认的int规则,其次它需要强制转换。

总而言之,无论如何,你应该只使用c ++代码:-P。

嗯,我认为这恰恰相反 - 总是直接将其转换为所需的类型。 请继续阅读!

<!> quot;忘了stdlib.h <!>争论是一个稻草人。现代编译器将检测并警告问题(gcc-Wall)。

您应该始终立即转换malloc的结果。不这样做应该被认为是一个错误,而不仅仅是因为它会像C ++一样失败。例如,如果您的目标是使用不同类型的指针进行机器架构,那么如果您不进行演员投放,最终可能会遇到一个非常棘手的错误。

修改:评论员 Evan Teran 是正确的。我的错误是认为编译器不必在任何上下文中对void指针进行任何操作。当我想到FAR指针错误时,我发飙,所以我的直觉就是抛出一切。谢谢Evan!

实际上,强制转换可以隐藏错误的唯一方法是,如果您要从一种数据类型转换为较小的数据类型并丢失数据,或者您将梨转换为苹果。请看以下示例:

int int_array[10];
/* initialize array */
int *p = &(int_array[3]);
short *sp = (short *)p;
short my_val = *sp;

在这种情况下,转换为short将从int中删除一些数据。然后这个案例:

struct {
    /* something */
} my_struct[100];

int my_int_array[100];
/* initialize array */
struct my_struct *p = &(my_int_array[99]);

你最终会指向错误的数据类型,甚至是无效的内存。

但总的来说,如果你知道自己在做什么,那么进行投射是可以的。当你从malloc获得内存时更是如此,这恰好返回一个你无法使用的void指针,除非你施放它,并且大多数编译器会警告你,如果你正在向lvalue投射(值为无论如何,任务的左侧都无法接受。

#if CPLUSPLUS
#define MALLOC_CAST(T) (T)
#else
#define MALLOC_CAST(T)
#endif
...
int * p;
p = MALLOC_CAST(int *) malloc(sizeof(int) * n);

或者,或者

#if CPLUSPLUS
#define MYMALLOC(T, N) static_cast<T*>(malloc(sizeof(T) * N))
#else
#define MYMALLOC(T, N) malloc(sizeof(T) * N)
#endif
...
int * p;
p = MYMALLOC(int, n);

人们已经列举了我通常小跑的原因:旧的(不再适用于大多数编译器)关于不包括stdlib.h和使用sizeof *p以确保类型和大小始终匹配而不管以后更新的论点。我想指出另一个反对施法的论点。这是一个小的,但我认为它适用。

C的输入相当弱。大多数安全类型的转换都是自动发生的,大多数不安全的转换需要强制转换。考虑:

int from_f(float f)
{
    return *(int *)&f;
}

这是危险的代码。它在技术上是未定义的行为,但在实践中它几乎在你运行它的每个平台上做同样的事情。演员阵容有助于告诉你 <!>;这段代码是一个可怕的黑客。<!>

考虑:

int *p = (int *)malloc(sizeof(int) * 10);

我看到一个演员,我想知道,<!>“为什么这是必要的?黑客在哪里?<!>它抬起我的脖子上的毛发,有一些邪恶的事情发生,事实上代码是完全无害的。

只要我们使用C,强制转换(特别是指针强制转换)就是说“!”的方式;这里有一些邪恶且易于破解的东西。<!> quot;他们可能会完成你需要完成的任务,但是他们向你和未来的维护人员表明孩子们不正常。

在每个malloc上使用强制转换会减少<!>“hack <!>”;指针转换的指示。它使得看到像*(int *)&f;这样的东西不那么刺耳。

注意:C和C ++是不同的语言。 C是弱类型的,C ++的类型更强。在C ++中,强制转换,即使它们根本不表示黑客攻击,因为(以我的拙见)不必要的强大的C ++类型系统。 (实际上,这个特殊情况是我认为C ++类型系统唯一的地方<!>“太强了,<!>”;但我想不出任何地方<!>“太弱,< !>“这使得我的口味总体上太强了。”

如果您担心C ++兼容性,请不要这样做。如果您正在编写C,请使用C编译器。每个平台都有很多非常好的产品。如果出于某种无聊的原因,你已经编写C ++编译干净的C代码,那么你真的不是在编写C语言。如果你需要将C语言移植到C ++,你应该做很多改动使你的C代码更加惯用C ++。

如果你不能做到这一点,无论你做什么,你的代码都不会很漂亮,所以你决定在那时投射并不重要。我喜欢使用模板创建一个返回正确类型的新分配器的想法,尽管这基本上只是重新发明new关键字。

将一个返回(void *)的函数转换为(int *)是无害的:你将一种指针转换为另一种指针。

将一个返回整数的函数转换为指针很可能是不正确的。如果您没有明确地投射它,编译器会标记它。

一个可能的错误(取决于这是你真正想要与否)是用一个大小规模进行mallocing,并分配给不同类型的指针。如,

int *temp = (int *)malloc(sizeof(double));

在某些情况下,您可能希望这样做,但我怀疑它们很少见。

我认为你应该把演员投入。考虑到类型有三个位置:

T1 *p;
p = (T2*) malloc(sizeof(T3));

这两行代码可能会分开。因此,编译器强制执行 T1 == T2。更容易直观地验证T2 == T3。

如果你错过了T2演员阵容,那么你必须希望T1 == T3。

另一方面,你有缺少的stdlib.h参数 - 但我认为它不太可能是一个问题。

另一方面,如果您需要将代码移植到C ++,最好使用'new'运算符。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top