为什么 sizeof 的赋值会改变从 size_t 赋值给 int 的变量类型?

Why does assignment from sizeof alter type of variable being assigned from size_t to int?

此程序编译时没有警告,并提供了预期的输出。

#include <stdio.h>
#include <stddef.h>

int i;
size_t s = sizeof(i);

int main(void){
    printf("%zu \n", s);
}

但是这个程序没有编译,我观察到以下警告和错误:

#include <stdio.h>
#include <stddef.h>

int i;
size_t s; 
s = sizeof(i);

int main(void){
    printf("%zu \n", s);
}

警告和错误:

    $ gcc -std=c99 -o sizeof_test sizeof_test.c 
sizeof_test.c:6:1: warning: data definition has no type or storage class [enabled by default]
 s = sizeof(i);
 ^
sizeof_test.c:6:1: warning: type defaults to ‘int’ in declaration of ‘s’ [enabled by default]
sizeof_test.c:6:1: error: conflicting types for ‘s’
sizeof_test.c:5:8: note: previous declaration of ‘s’ was here
 size_t s; 
        ^
sizeof_test.c: In function ‘main’:
sizeof_test.c:9:5: warning: format ‘%zu’ expects argument of type ‘size_t’, but argument 2 has type ‘int’ [-Wformat=]
     printf("%zu \n", s);
     ^

这是 gcc 版本信息:

$ gcc --version
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.1) 4.8.4
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

我的理解是,至少对于 c99 和可能更早的版本,sizeof 有一个 return 类型的 size_t,例如 stated at cppreference.

如果是这样,那么从 sizeof 赋值怎么会导致某些隐式类型转换为 int 而不是作为 size_t 变量的直接初始化完成? ssizeof运算符的return类型都不是int,那么int类型从何而来呢?

真正的问题是,你不能在所有函数之外赋值变量。

size_t s; 
s = sizeof(i);

这两行被解释为:一个全局变量s,类型为size_t,以及另一个全局变量s,类型为隐式int(C99无效),用sizeof(i)初始化。

如果你明白这一点,你就能理解所有的error/warning消息。它们要么与 s 的隐式 int 类型相关,要么与定义了两种不同类型的 s 相关。

问题是您只能在全局范围内定义变量(带有可选的初始值设定项)。你不能有可执行语句。

当编译器在全局范围内看到它时:

s = sizeof(i);

由于那里不能存在语句,因此假定它是一个变量声明。您收到的错误和警告如下:

  • 由于声明没有定义类型,类型默认为 int,您会收到针对这两种情况的警告。
  • 然后你会得到类型冲突的错误,因为这个隐式定义的 int 与上一行定义的 size_t 同名。
  • 有关无效 printf 格式说明符的警告也随之而来,因为 s 的最新定义是 int