我在多个地方都读过,在声明一个extern变量时,直到定义完成后才指定内存。我正在尝试这段代码在gcc中给出矛盾的输出。
#include <stdio.h>
int main() {
extern int a;
printf("%lu", sizeof(a));
return 0;
}
应该显示错误或大小为零。但输出如下。请证明输出的合理性。这是另一个未定义行为的示例吗?
aditya@theMonster:~$ ./a
4
答案 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_t
和printf
具有不同的大小或表示形式,则为%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
没有在任何地方定义。