我在微软文章中阅读了以下信息;
https://support.microsoft.com/en-us/kb/44463
下面的文本提供了一个常见编程错误的示例,即混淆数组和指针声明: 考虑将应用程序分为几个模块。在一个模块中,声明一个数组如下:
signed char buffer[100];
在另一个模块中,声明以下变量以访问该数组:
extern signed char *buffer; // FAILS extern signed char buffer[]; // WORKS
如果您在CodeView调试器中查看代码,则表明
*buffer
声明产生的地址与buffer[]
声明的地址不同。
但我无法理解为什么我们无法使用*buffer
访问该数组
我们可以使用buffer[]
访问它。
请有人解释一下这两种类型有什么区别?
答案 0 :(得分:3)
extern signed char buffer[];
是拥有地址的一块内存。
extern signed char *buffer;
是可能或可能不指向一块内存的变量 - 它是包含一个可能有效或无效的地址的变量。
答案 1 :(得分:1)
之间的差异
extern signed char *buffer;
extern signed char buffer[];
与您在
时看到的相同signed char *buffer;
signed char buffer[100];
在一个函数中。
我看到以下差异:
差异1
当你有:
extern signed char *buffer;
你可以使用:
buffer = malloc(10);
当你有:
extern signed char buffer[];
你做不到。
差异2
在第一种情况下,buffer
可能为NULL。在第二种情况下,它不是。
差异3
&buffer
会产生不同的类型。例如,您可以使用:
printf("pointer 1: %p\n", &buffer+1);
在第一种情况下但你不能在第二种情况下使用它。要让&buffer+1
在第二种情况下工作,您必须知道数组的大小。
答案 2 :(得分:1)
这个问题更多的是关于C链接器而不是关于C语言。
虽然signed char *buffer
和signed char buffer[]
的含义相同,但extern
不是其中之一。使用extern
要求编译器将外部定义的解析推迟到链接器。链接器必须非常讲究指针和数组之间的区别,因为它们在内存中具有不同的结构,并且不能互换处理。
请注意,尽管这些声明与链接器不同,但它们并不会改变程序员使用这样的外部数组所做的事情:在这两种情况下,您都无法访问声明的数组的大小(即100),语法访问数组元素保持不变,指针算法保持不变。
答案 3 :(得分:1)
在一个模块中,您定义一个名为signed char
的{{1}}大小为100
的数组。该对象将使用100个字节的内存:
buffer
在另一个模块中,你声明 signed char buffer[100];
是另一个东西,指向buffer
的指针,即4或8字节的内存,可以保存一个地址数组或单个signed char
的数组。
char
编译器一次只知道一个模块,因此无法检查此声明是否与实际的定义一致。它与此声明一致地编译代码,发出引用外部符号extern signed char *buffer;
的机器代码,该外部符号将在链接时解析。
在链接时,链接器不知道类型,它只依赖于名称。因此,它从一个模块解析对buffer
的引用,并使用另一个模块中的定义的实际地址。
在运行时,您会得到未定义的行为,因为一个模块使用buffer
作为buffer
的数组,它是,而另一个模块从同一地址加载指针的值,解释字节完全不同。
声明属于标头文件,并且应始终包含在实际定义对象的源文件中标题中声明。
答案 4 :(得分:1)