声明外部类变量后的内存分配

时间:2019-02-11 18:47:04

标签: c

我在多个地方都读过,在声明一个extern变量时,直到定义完成后才指定内存。我正在尝试这段代码在gcc中给出矛盾的输出。

#include <stdio.h>

int main() {
    extern int a;
    printf("%lu", sizeof(a));
    return 0;
}

应该显示错误或大小为零。但输出如下。请证明输出的合理性。这是另一个未定义行为的示例吗?

aditya@theMonster:~$ ./a
4

5 个答案:

答案 0 :(得分:3)

您可以在这里摆脱它,因为从未真正使用过a。表达式sizeof(a)在编译时求值。因此,由于从未引用过a,因此链接程序不会费心寻找它。

您改为这样做吗?

printf("%d\n", a);

然后该程序将无法链接,并显示“对'a'的未定义引用”

答案 1 :(得分:2)

变量的大小是其数据类型的大小,无论当前是否仅为extern。由于sizeof是在编译时评估的,而符号解析是在链接时完成的,所以这是可以接受的。

即使使用-O0,gcc也不关心它是extern;它将4放在esi中作为printf的参数:https://godbolt.org/z/Zv2VYd

但是,如果不声明a,以下任何一项将失败:

a = 3;
printf("%d\n", a);
int *p = &a;

答案 2 :(得分:2)

a是一个整数,因此其大小为4。

位置(地址)和目前未知。
(在其他位置的某个地方extern

但是 size 定义明确。

答案 3 :(得分:1)

oid 1是一元运算符,当不提供可变长度数组时,不对表达式求值。它只是检查表达式的数据类型。

类似地,此处,在must appear in the GROUP BY clause or be used in an aggregate function中,编译器仅检查size_t sizeof(expr/var_name/data_type)的数据类型sizeof(a),因此返回a的大小。

另一个清除您的困惑的示例是在int中,我没有得到增加。其数据类型已检查并返回。

另一个例子:

int

会将u在gcc上的输出显示为:

sizeof(i++)

答案 4 :(得分:0)

您的代码中确实存在问题,但是您期望的地方却没有问题:

  • 如果size_tprintf具有不同的大小或表示形式,则为%ld转换规范size_t传递类型为unsigned long的值具有不确定的行为,在许多系统上(例如16位系统,Windows 64位...)。

这里是经过纠正的版本,可移植到不符合C99的系统,其C库printf可能不支持%zu

#include <stdio.h>

int main(void) {
    extern int a;
    printf("%lu\n", (unsigned long)sizeof(a));
    return 0;
}

关于程序为何正确编译并执行:

  • 变量a是通过main链接声明在extern主体内部的:没有为其分配空间,并且a在{{1主体之外}}。
  • main在编译时被评估为常量值sizeof(a),在您的平台上恰好是sizeof(int)
  • 编译器不会进一步引用4,因此链接器不会抱怨a没有在任何地方定义。