这些C外部定义之间的区别是什么?

时间:2015-04-12 13:50:10

标签: c arrays extern avr-gcc

我在调试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加nsizeof(struct mystruct)

仅在我将定义更改为

之后
extern struct mystruct mystruct_array[COUNT];

(与main.c完全相同),我得到了数组的真实地址。

我的问题:为什么这会对编译器产生影响(在我的例子中是avr-gcc)?

3 个答案:

答案 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声明,在一个文件中放置一个定义。例如,

header.h

extern struct mystruct mystruct_array[];
/* or extern struct mystruct mystruct_array[COUNT] */

的main.c

#include "header.h"

#define COUNT 10
/* should have an initializer to be a definition: */
struct mystruct mystruct_array[COUNT] = { 0 };

/* ... */

other.c

#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!

当您链接程序时,如果您没有指示链接器链接包含该结构的对象,您将获得未定义的引用!