我在调试AVR微控制器时遇到了这个问题: 我有一个带有大量变量定义的main.c文件,其中包括一个结构数组,如下所示:
struct mystruct mystruct_array[COUNT];
在另一个.c文件中,我把这个数组称为外部,但是我放弃了数组括号和大小,所以我不会重复自己,只是将变量声明为指针(因为数组本质上是指针,不是它们):
extern struct mystruct *mystruct_array;
但是当我使用printf("%p\n", mystruct_array);
检查数组的地址时,我得到一个空指针而不是数组在内存中的位置。此外,如果我要访问数组中的后续项目,例如printf("%p\n", &(mystruct_array[n]));
,则会打印地址0加n
次sizeof(struct mystruct)
。
仅在我将定义更改为
之后extern struct mystruct mystruct_array[COUNT];
(与main.c完全相同),我得到了数组的真实地址。
我的问题:为什么这会对编译器产生影响(在我的例子中是avr-gcc)?
答案 0 :(得分:8)
这很有趣。
当你写:
struct mystruct mystruct_array[COUNT];
您创建了mystruct
个结构的全局数组,其中有COUNT
个结构,并且由于您没有对其进行初始化,因此它将填充零。
然后写下:
extern struct mystruct *mystruct_array;
您告诉编译器某处有一个名为mystruct_array
的变量,并且它是一个指针。但事实并非如此,它是一个阵列。因此,编译器将读取数组的内容,就像它是一个指针一样。
因此,当您尝试输出该指针的值时,编译器将在内存中获取mystruct_array
并输出其内容,就好像它是一个指针一样。因为它实际上是一个充满零的数组,所以你在输出中看到一个空指针。
相反,你应该写一些像:
extern struct mystruct mystruct_array[];
因此编译器知道变量的正确类型。您可以在此处的方括号中指定长度,但您不必这样做。
我建议您继续阅读the differences between pointers and arrays,以确保将来不要混淆。{3}}
答案 1 :(得分:2)
执行此操作的理想方法是在头文件中放置extern
声明,在一个文件中放置一个定义。例如,
extern struct mystruct mystruct_array[];
/* or extern struct mystruct mystruct_array[COUNT] */
#include "header.h"
#define COUNT 10
/* should have an initializer to be a definition: */
struct mystruct mystruct_array[COUNT] = { 0 };
/* ... */
#include "header.h"
/* ... */
printf("%p\n", mystruct_array);
这可以节省您的重复次数,并限制您可能需要进行更改的位置。请注意,如果您的标头没有定义数组中的元素数,那么您不能将sizeof
操作应用于除提供数组定义的文件之外的其他文件中。{/ p>
另请注意,虽然数组不是指针,但在C源代码的大多数上下文中,数组名称已转换指向指向第一个元素的指针阵列。这是数组是指针的误解的根源。虽然它们不是指针,但在很多方面它们都表现得好像。
答案 2 :(得分:0)
extern的声明意味着声明的对象在另一个C文件中是全局的。然后,当您生成目标文件时,如果声明的对象(在本例中为结构)不存在,也会生成它。
如果您声明:
extern struct structname * s;
表示在另一个C模块中有一个指向结构structname s的全局可见指针。
如果您声明:
extern struct structname s;
意味着在另一个C模块中有一个全局可见结构structname s!
当您链接程序时,如果您没有指示链接器链接包含该结构的对象,您将获得未定义的引用!