gan*_*ars 7 c gcc declaration sizeof
我最近尝试过这段代码并且有点困惑.请参阅以下声明:
static st;
auto au;
register reg;
volatile vl;
const cn;
Run Code Online (Sandbox Code Playgroud)
它们都分配4个字节的内存(在32位GCC上).但是当我尝试打印(使用printf功能)他们的尺寸时,他们没有工作并且出错.
sizeof(const) // worked and printed 4
sizeof(volatile) // worked and printed 4
sizeof(auto) // error: expected expression before ‘auto’
sizeof(static) // error: expected expression before ‘static’
sizeof(register) // error: expected expression before ‘register’
Run Code Online (Sandbox Code Playgroud)
我怀疑是auto, static, register 关键字还分配4字节的内存(在32位拱门上).
但是,为什么这些是给错误不像const和volatile?
Kei*_*son 17
在1999标准之前的C中,未指定的类型int在许多情况下都是默认的.
C99放弃了该规则,省略该类型现在是非法的(严格来说,这是违反约束,需要诊断 - 这可能是一个非致命的警告).在任何情况下,省略int类型一直是个坏主意.(它可以追溯到C的前身语言BCPL和B,其中很大程度上没有类型.)
static st;
auto au;
register reg;
volatile vl;
const cn;
Run Code Online (Sandbox Code Playgroud)
这些声明在C90中都是合法的(并且所有变量都是类型的int),但它们在C99中是无效的.
sizeof(const)
sizeof(volatile)
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,这些在C90中实际上是合法的(但不是在C99中).const或者volatile它本身是一个类型名称,分别等同于const int和volatile int.在语法上,const并且volatile是类型修饰符.
sizeof(auto)
sizeof(static)
sizeof(register)
Run Code Online (Sandbox Code Playgroud)
区别在于:
const int x = 42;
Run Code Online (Sandbox Code Playgroud)
定义x为类型的对象const int,而这:
static int x = 42;
Run Code Online (Sandbox Code Playgroud)
定义x为类型的静态对象int(static不属于该类型).
这些都是语法错误,因为auto,static和register不键入名称.这些关键字是存储类说明符.
这解释了为什么前两个sizeof表达式似乎有效,而其他表达式则无效.但是要知道这一点并不是特别有用,因为如果你指定了类型int(你总是应该这样),那么sizeof(const)碰巧是有效的(在C90中,而不是在C99中)并不重要.
最重要的是,您应该始终在任何声明中指定类型.虽然你可以合法地写sizeof (const int),但它保证是相同的sizeof (int),所以const在这种情况下使用没有多大意义.
Sha*_*our 10
在C99之前,如果你没有指定一个类型,那么将隐含int,这就是你的代码中发生的事情.它在实践中看起来甚至在C99模式下gcc,clang只会产生警告.这是编译器警告是你的朋友的情况,我试过这个clang -Wall:
printf( "%zu\n", sizeof(const) ) ;
Run Code Online (Sandbox Code Playgroud)
它警告我:
warning: type specifier missing, defaults to 'int' [-Wimplicit-int]
Run Code Online (Sandbox Code Playgroud)
这里的所有声明:
static st;
auto au;
register reg;
volatile vl;
const cn;
Run Code Online (Sandbox Code Playgroud)
也有隐含的int类型.
我们可以看到C99 删除了隐式int假设:
缺少类型说明符的声明不再具有隐式假定的int.C标准委员会认为,编译器诊断无意中遗漏类型说明符比静默处理依赖于隐式int的遗留代码更有价值.在实践中,编译器可能会显示警告,然后假设为int并继续翻译程序.
如果我们看一下C99标准草案, 前言部分第5段包括以下内容:
[...]上一版的主要变化包括:
并有以下子弹:
- 删除隐式int
更新
那么为什么不sizeof喜欢像static和auto这样的存储类说明符,但是对于const和volatile这样的类型限定符是好的,这种行为似乎与声明的工作方式不一致,并且隐式int假设是否仍然有效?
好吧,如果我们sizeof在草案标准部分查看语法,6.5.3它如下:
sizeof unary-expression
sizeof ( type-name )
Run Code Online (Sandbox Code Playgroud)
因此,类型限定符和存储类说明符都不是表达式,但类型限定符是类型名称,如果我们查看类型名称6.7.6的语法如下:
type-name:
specifier-qualifier-list abstract-declaratoropt
Run Code Online (Sandbox Code Playgroud)
并6.7.2.1给出了说明符限定符列表的语法,如下所示:
specifier-qualifier-list:
type-specifier specifier-qualifier-listopt
type-qualifier specifier-qualifier-listopt <- Bingo allows type qualifier
Run Code Online (Sandbox Code Playgroud)
所以我们可以看到,即使将类型显式指定为int,也sizeof只是不接受存储类说明符,所以即使以下是错误:
printf( "%zu\n", sizeof(static int) ) ;
Run Code Online (Sandbox Code Playgroud)
并clang告诉我们:
error: expected expression
printf( "%zu\n", sizeof(static int) ) ;
^
Run Code Online (Sandbox Code Playgroud)
我们可以进一步看到,如果没有以下类型名称将无法使用:sizeof()
printf( "%zu\n", sizeof int ) ;
Run Code Online (Sandbox Code Playgroud)
产生错误:
error: expected expression
Run Code Online (Sandbox Code Playgroud)
但一元表达式一起工作(),因为我先前说明这里.