外部声明,T * v / s T

我在遗留项目中看到了以下代码片段。

/* token.c */ struct token id_tokens[MAX_TOKENS]; /* analyse.c (v1) */ extern struct token *id_tokens; /* Raised my eyebrow, id_token declares a pointer */ 

我坚持要更改analyse.c以包含如下声明:

 /* analyse.c (v2) */ extern struct token id_tokens[]; /* I am happy with this. id_tokens declares array of unspecified size. */ 

我想要v2因为pointer to T array of T 。 我朋友的反驳说,两者的行为都是一样的,所以我使用v1和v2并不重要。

问题1:不完整类型的数组是否耗尽指针?

问题2:我的朋友是否正确,两个版本在行为上都保证等同?

 /* token.c */ struct token id_tokens[MAX_TOKENS]; /* id_tokens +-----+-----+-----+-----+...+-----+ | | | | | | | +-----+-----+-----+-----+...+-----+ [0] [1] [2] [3] ... [MAX_TOKEN-1] To access id_tokens[i], add offset of ith element ie i * sizeof(struct token) to the **address** of array token */ 

因此,在您的analyse.c ,将使用此声明生成以下说明。

  1. extern struct token id_tokens[];
    id_tokens [I]
    一个。 可以从其他编译单元链接的id_tokens的地址被采用
    湾 i的偏移量被添加
    C。 值被引用
 /* analyse.c (v1) */ extern struct token *id_tokens; /* id_tokens +------+ +-----+... | addr |---------->| | +------+ +-----+... To access id_tokens[i], fetch **contetnts** of pointer token, add offset of ith element ie i * sizeof(struct token) is added to this. */ 

因此,在您的analyse.c ,将使用此声明生成以下说明:

  1. extern struct token *id_tokens;
    id_tokens [I]
    一个。 从其他编译单元链接的id_tokens的地址的内容被采用。
    (如果由于类型不匹配而存在于同一编译单元中,将导致编译错误)
    湾 i的偏移量被添加
    C。 值被引用

假设id_token[0] sizeof是2字节,而id_token[0] sizeof指针是4字节。

您之后的声明可能(错误地)将id_tokens[0]id_tokens[1]为地址并向其添加一些偏移量(可能是现有的或不存在的地址,已知的对齐或非对齐地址)。

如果这是您的好日子,程序可能会立即崩溃或发生段错​​误,您将有机会修复该错误。 如果这是你糟糕的一天,程序可能只是搞乱了一些其他内存或者将错误的状态传达给某个模块,这可能导致难以跟踪错误并导致噩梦。


现在我猜你明白为什么你在32的回答中得到(nil)作为输出。

第一个版本是错误的。 数组不是指针,声明extern struct token *id_tokens; 与定义类型struct token id_tokens[MAX_TOKENS];不匹配struct token id_tokens[MAX_TOKENS];

参考: C FAQ:我在一个源文件中定义了char [6],在另一个源文件中我声明了extern char * a。 它为什么不起作用? 。 另外,看到这个 。

让我们按程序理解相同的东西

test.c的

 #include #include"head.h" struct token id_tokens[10]; int main() { printf("In original file: %p",id_tokens); testing(); } 

head.h

 struct token { int temp; }; 

test1.c与v1

 #include #include"head.h" extern struct token* id_tokens; void testing () { printf("In other file %p",id_tokens); } 

输出:原始文件:0x601040其他文件(无)


test1.c with v2

 #include #include"head.h" extern struct token id_tokens[]; void testing () { printf("In other file %p",id_tokens); } 

输出:在原始文件中:0x601040在其他文件0x601040中


这清楚地表明v1不正确且v2正确。