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

C 什么';这些外部定义之间的区别是什么?,c,arrays,extern,avr-gcc,C,Arrays,Extern,Avr Gcc,我在调试AVR微控制器时遇到了这个问题: 我有一个包含许多变量定义的main.c文件,其中有一个结构数组,如下所示: struct mystruct mystruct_array[COUNT]; 在另一个.c文件中,我将此数组称为外部数组,但我省略了数组括号和大小,因此我不会重复自己的操作,而是将变量声明为指针(因为数组本质上是指针,不是吗?) 但是当我使用printf(“%p\n”,mystruct\u数组)检查数组的地址时I得到了一个空指针,而不是数组在内存中的位置。另外,如果我要访问数组

我在调试AVR微控制器时遇到了这个问题: 我有一个包含许多变量定义的main.c文件,其中有一个结构数组,如下所示:

struct mystruct mystruct_array[COUNT];
在另一个.c文件中,我将此数组称为外部数组,但我省略了数组括号和大小,因此我不会重复自己的操作,而是将变量声明为指针(因为数组本质上是指针,不是吗?)

但是当我使用
printf(“%p\n”,mystruct\u数组)检查数组的地址时
I得到了一个空指针,而不是数组在内存中的位置。另外,如果我要访问数组中的后续项,如
printf(“%p\n”&(mystruct_array[n])它将打印地址0加
n
sizeof(struct mystruct)

只有在我把定义改为

extern struct mystruct mystruct_array[COUNT];
(与main.c完全相同),我得到了数组的真实地址

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

这是一个有趣的问题

当你写作时:

struct mystruct mystruct_array[COUNT];
您创建了一个全局数组
mystruct
struct,其中有
COUNT
,由于您没有初始化它,它将被零填充

当你写下:

extern struct mystruct *mystruct_array;
您告诉编译器,在某个地方有一个名为
mystruct\u array
的变量,它是一个指针。但它不是,它是一个数组。因此编译器将读取数组的内容,就像它是指针一样

因此,当您尝试输出该指针的值时,编译器将在内存中获取
mystruct\u array
,并将其内容作为指针输出。因为它实际上是一个满是零的数组,所以在输出中会看到一个空指针

相反,你应该写下如下内容:

extern struct mystruct mystruct_array[];
因此编译器知道变量的正确类型。您可以在此处的方括号中指定长度,但不必指定


我建议你去仔细阅读,以确保将来不会混淆它们

extern的声明意味着声明的对象在另一个C文件中是全局的。然后,在生成对象文件时,如果声明的对象(在本例中为结构)不存在,也会生成该文件

如果您声明:

extern struct structname * s;
extern struct structname s;
意味着在另一个C模块中有一个指向结构名structname s的全局可见指针

如果您声明:

extern struct structname * s;
extern struct structname s;
意味着在另一个C模块中有一个全局可见结构名Structs


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

实现这一点的理想方法是将
extern
声明放在头文件中,而定义正好放在一个文件中。比如说,

标题.h main.c 其他 这样可以避免重复,并限制可能需要进行更改的位置。请注意,如果标头未定义数组中的元素数,则不能将
sizeof
操作应用于除提供数组定义的文件之外的其他文件中的该数组


还要注意的是,尽管数组不是指针,但在C源代码中的大多数上下文中,数组名被转换为指向数组第一个元素的指针。这是错误理解数组是指针的根源。虽然它们不是指针,但在许多方面,它们的行为就像它们是指针一样。

数组不是指针。指针不是数组。花一个周末在湖边喝杯咖啡来思考这个问题,你的余生将是金色的。@Kerrek SB:对不起,当我将我的特定代码更改为这个更一般的示例时,我忘记了这一点。我的意思是
mystruct\u数组
。好的,不用担心。对于未来的问题,请记住:在发布之前请重新阅读:-)您可以合理地声明
extern struct mystruct mystruct_array[]如果不方便将计数暴露在定义结构的文件之外。当然,避免使用globals通常是个好主意。实际上,
extern
声明应该包含在
main.c
other.c
文件中的头文件中。这将为您提供对类型的正确交叉检查。另请参见总结,该程序的格式不正确,因为它使用不同的类型两次声明相同的名称?@JoeZocker数组基本上只是内存中的一块数据。指针是一个数字,它告诉您在哪里可以找到该数据块。让很多人困惑的是数组可能会退化为指针。我无法在注释中为您编写完整的教程,但请确保“extern…”中的类型与定义的类型匹配,这样您就没事了。当我第一次将数组声明为
struct mystruct mystruct\u array[]
时,我也可以稍后将第一个元素的地址简单地称为
mystruct\u array
。如果我想要内容(在这种情况下是零),我会取消引用该指针(
*mystruct\u数组
==
mystruct\u数组[0]
)。那么,为什么数组表示法与指针表示法不同呢?“我稍后也可以简单地将第一个元素的地址称为
mystruct\u array
”,奇怪的是,您没有介绍数组的情况,我不否认我总是喜欢将它作为指针引用,在解释如何将它们声明为数组之前,我应该尝试:p…:)但是因为数组的名称是指针。。。是一样的!!!我对AVR的使用非常感兴趣!我开始使用它们,我觉得它很强大。。。现在我正在评估8位MCU:tiny 85/84、mega 168/328。我希望他们能成为我的新工作!
#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);