【问题标题】:Some mystic with 'extern' pointer to struct in C一些神秘的'extern'指针指向C中的结构
【发布时间】:2016-12-22 10:41:08
【问题描述】:

我有以下带有 3 个指向结构的全局指针的代码:

structs.h:

#pragma once

typedef struct Bignum {
  int digit;
  struct Bignum *next;
  struct Bignum *prev;
} Bignum;

typedef struct Stack {
  struct Bignum *head;
  struct Bignum *tail;
  char sign;
  struct Stack *next;
} Stack;

Bignum *num_tail;
Bignum *num_head;
Stack *stack_head;

globals.c:

#include "structs.h"

Bignum *num_tail;
Bignum *num_head;
Stack *stack_head;

当我用其他 .c 文件编译这些文件时(我包括 structs.h 并使用 num_tailnum_head 和 stack_head),编译器(clang 版本 3.8.0gcc 5.4.0)编译此代码没有错误并且程序可以运行正如它应该。但是,就我而言,由于 structs.h 中缺少 extern 修饰符,这段代码不应该正常编译和工作。为什么它有效? :)

UPD:是的,答案是暂定定义。实际上,在初始化指向NULL 的指针后,编译器会给出错误消息。谢谢大家的回复!

【问题讨论】:

  • 查找“暂定定义C”
  • 尝试将标题包含到 2 个不同的 .c 文件中,看看会发生什么......
  • 这里有一个link 到这个程序的存储库。标头包含在所有 .c 文件中,一切正常。
  • @LPs 什么都没有,因为gcc 会将两个文件的变量放入一个公共部分(FORTRAN 样式)。
  • LPs 通常是的,但gcc 有一个扩展名,在所有翻译单元中,未初始化的外部链接变量被组合(好像所有定义前面都有一个extern,除了一个)。

标签: c pointers struct extern


【解决方案1】:

暂定定义。您没有为这些全局变量赋值,因此它们被视为暂定定义。假设右侧={0};,但只是暂时的。如果没有真正的定义,暂定定义将被合并。如果有的话,它会在不产生链接器冲突的情况下战胜暂定的。这通常通过通用符号实现(在nm 输出中标记为C),这意味着即使在多个翻译单元中,您也可以对同一符号进行暂定定义。 (我认为最好不要依赖这个特性,坚持使用外部声明和非暂定定义。)

【讨论】:

    【解决方案2】:

    默认情况下不需要extern,因为非静态变量已经具有外部作用域。

    实际上globals.c 中的声明是多余的。

    Bignum *num_tail;
    Bignum *num_head;
    Stack *stack_head;
    

    编译器只会在重新定义的情况下给出错误,例如,如果标头和源中的num_tail 都已初始化

    【讨论】: