为什么C编译器没有警告malloc大小错误?

时间:2016-10-05 06:32:38

标签: objective-c c struct malloc

我创建了一个我在iOS应用程序的ViewDidLoad中指定的成员结构。我使用malloc为这个结构分配空间,然后在我的课程中使用它。像这样:

self.myData = malloc(sizeof(MyData));

除了我真正做的是这个:

self.myData = malloc(sizeof(MyOtherStruct));

我不小心将malloc调用中的sizeof()设置为不同的结构(大小不同)。我很长时间没有注意到这个错误,因为应用程序很少崩溃。对操作系统的更新导致崩溃更频繁发生。

我的问题是,为什么编译器不会对这类事情发出警告?这是编译器不知道的东西,或者它是一种设计选择,允许用户使用它们喜欢的任何尺寸吗?

2 个答案:

答案 0 :(得分:4)

“如何更快地找到此错误?”

有很多方法可以更快地找到错误。

解决方案#1

静态分析器发现此错误。在Xcode中按下命令shift-B。例如,请使用以下代码:

#include <stdlib.h>

struct x { double x; };
struct y { char y; };

int main(int argc, char **argv) {
    struct x *p = malloc(sizeof(struct y));
    p->x = 1.0;
    return 0;
}

运行分析器会为我生成此错误:

  

'malloc'的结果被转换为'struct x'类型的指针,该指针与sizeof操作数类型'struct y'不兼容

解决方案#2

建议以这种方式编写代码:

self.myData = malloc(sizeof(*self.myData));

将来这样做吧。这不仅容易出错,而且更容易记住。

解决方案#3

使用像Swift或C ++这样的语言,语言的类型系统可以帮助您避免这种错误。 C在很多方面都不太宽容。它是在20世纪70年代早期发明的,你只需要接受它,如果你想使用它,这些类型的错误是主要的部分原因C ++和Swift甚至存在于第一名。

解决方案#4

使用运行时内存边界检查程序,如地址清理程序。这将在访问内存时检测错误,而不是在分配时检测错误,但它仍然会为访问和分配提供堆栈跟踪(如果已释放内存,则为空闲)。这些天写C的人应该熟悉地址消毒剂及其朋友tsan,ubsan等。

Valgrind也达到了同样的效果,但地址消毒剂对于常见用例具有更好的用户体验。

问题

编译器只会为您提供类型错误的错误和警告。这不是类型错误,而是运行时错误。编译器可以检测到一些“可能的”运行时错误,但它们的数量非常少。忘记使用malloc()的返回值......例如,

void f(void) {
    malloc(1); // warning
}

编译器没有那么好。

同样,这是C ++和Swift等新语言的推动力,它们具有允许您在错误分配事物时生成错误的类型系统,这也是静态分析的推动力(这是一个棘手的问题)。

答案 1 :(得分:0)

这是因为ARC不负责处理malloc()甚至free()

ARC只处理分配的对象[Object alloc]

在您的情况下,当您执行self.myData = malloc(sizeof(MyOtherStruct));时,可以使用以下内容进行解释:

self.myData = malloc(N*sizeof(MyData));
//what can represents self.myData[0]..self.myData[N-1]

最后,请记住,当你使用sizeof()时,它会告诉你类型的大小,你作为参数传递,在编译时计算。

您可以查看此Here以获取有关对象分配的更多信息

并查看有关link

的Apple文档