外部声明,T*v/s T []

Gya*_*ain 8 c declaration extern language-lawyer

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

/* token.c */
struct token id_tokens[MAX_TOKENS];

/* analyse.c (v1) */
extern struct token *id_tokens; /* Raised my eyebrow, id_token declares a pointer */
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

问题2:我的朋友是对的,两个版本在行为上都保证是等价的吗?

Yu *_*Hao 8

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

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


Moh*_*ain 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
  i.e. i * sizeof(struct token) to the **address**
  of array token
 */
Run Code Online (Sandbox Code Playgroud)

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

  1. extern struct token id_tokens[];
    id_tokens[i]
    a. 获取可能从其他编译单元链接的 id_tokens 的地址
    b.添加 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 i.e. i * sizeof(struct token)
  is added to this.
 */
Run Code Online (Sandbox Code Playgroud)

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

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

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

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

如果今天运气好,程序可能会立即崩溃或出现段错误,并且您有机会修复错误。如果今天心情不好,程序可能会弄乱其他内存或向某些模块传达错误的状态,这可能会导致难以跟踪错误并引发噩梦。


现在我想你明白为什么你在32 先生的答案(nil)中得到了输出。