在malloc中输入类型
这个问题在这里已经有了答案:
如果您没有#include
d stdlib.h
, malloc
的返回值在返回到调用代码之前很可能被截断。 从理论上讲,这是未定义的行为。 如果malloc
的返回值被截断,则类似于使用:
int a = 10;
int* ap = &a;
int temp = (int)ap; // This is where you lose the pointer value due to truncation.
int* bp = (int*)temp;
你的房子宽50英尺。 你的家庭地址是'40,Church st,Newtown'。 说你家旁边有沃尔玛或学校等大型商店。 这是450英尺宽。 但地址是'50,Church St,Newtown'。
您是否需要使用不同尺寸的纸张来书写这些地址,因为一个纸张比其他纸张大? 当然不是。 指针与地址同义。 它是位置。 那里存储的(在你的情况int 4字节)不会改变地址长度。
所以最后,x的大小为8,并且将指向4字节的大小。
让我们看看会发生什么。 假设这个代码:
#include <stdio.h>
int main(int argc, char ** argv) {
printf("sizeof(int) = %zunsizeof(int *) = %zun",
sizeof(int), sizeof(int *));
// output:
// sizeof(int) = 4
// sizeof(int *) = 8
int * foo = (int *) malloc(sizeof(int));
return 0;
}
在我的系统上用clang ouch.c
编译这个结果给出:
ouch.c:5:23: warning: implicitly declaring library function 'malloc' with type 'void *(unsigned long)'
int * foo = (int *) malloc(sizeof(int));
^
ouch.c:5:23: note: include the header <stdlib.h> or explicitly provide a declaration for 'malloc'
在这里,clang足够聪明,能够注意到我调用了malloc
,它是一个已知的库函数,并假定(正确)函数签名为void *(unsigned long)
。 所以一切都很好。 但不是每个编译器都很聪明,我也可以欺骗铛:
#include <stdio.h>
int main(int argc, char ** argv) {
printf("sizeof(int) = %zunsizeof(int *) = %zun",
sizeof(int), sizeof(int *));
int * foo = (int *) wrapper();
return 0;
}
在一个单独的文件中,我将链接到上面的主文件:
#include <stdlib.h>
void * wrapper(void) {
return malloc(sizeof(int));
}
运行clang wrapper.c ouch2.c
给我:
ouch2.c:5:23: warning: implicit declaration of function 'wrapper' is invalid in C99 [-Wimplicit-function-declaration]
int * foo = (int *) wrapper();
^
ouch2.c:5:15: warning: cast to 'int *' from smaller integer type 'int' [-Wint-to-pointer-cast]
int * foo = (int *) wrapper();
^
2 warnings generated.
这很不错,因为如果读取这些警告,那么很容易理解问题的根源并解决它们。 但如果我忽略它们并保持代码的状态,会发生以下情况:
编译ouch2.c
,clang没有看到任何wrapper
声明。 由于我从循环中删除了它的智能库函数检测,因此它别无选择,只能假设这被声明为某处
int wrapper();
这是一个函数,返回一个int
并获取任意数量的参数。 我们看到这样的证据,因为clang(作为一个智能编译器)警告我关于从(返回的) int
为int *
的第二个警告。
将int
转换为int *
并不是什么坏事。 什么是坏的假设,我们得到一个int
摆在首位。 假定在wrapper
函数中调用malloc
返回了这个值:
0xAABBCCDD11223344
然后会发生什么取决于调用约定。 让我们假设它将这个值作为返回值放入64位寄存器中。
main
调用代码需要一个int
,所以它只能从寄存器中读取32位(可能是下半部分)并使用它。 所以main
,我从wrapper
得到这个:
0x11223344
然后将其转换为(64位) int *
,可能导致:
0x0000000011223344
然后将其用作内存地址。 访问这个地址可能会(如果你幸运的话)导致分段错误或者(如果你不那么幸运)改变一些随机数据(如果发生在堆栈上,这会变得特别有趣,例如改变返回地址) 。
所以,最后但并非最不重要的是,如果我离开演员阵容:
#include <stdio.h>
int main(int argc, char ** argv) {
printf("sizeof(int) = %zunsizeof(int *) = %zun",
sizeof(int), sizeof(int *));
int * foo = wrapper();
return 0;
}
并用clang wrapper.c ouch3.c
编译clang wrapper.c ouch3.c
我得到:
ouch3.c:5:15: warning: implicit declaration of function 'wrapper' is invalid in C99 [-Wimplicit-function-declaration]
int * foo = wrapper();
^
ouch3.c:5:9: warning: incompatible integer to pointer conversion initializing 'int *' with an expression of type 'int' [-Wint-conversion]
int * foo = wrapper();
^ ~~~~~~~~~
2 warnings generated.
也是一个警告,但一个不同的警告。 这种(某种)警告更可能由您的编译器生成。
长话短说:clang能够很好地警告潜在的错误,并且不会抛出返回值,因为如果忘记包含stdlib.h,即使没有用clang编译,你也可以肯定会得到警告:)
链接地址: http://www.djcxy.com/p/28367.html下一篇: Casting errors in malloc for "char" array in C language