以下代码中枚举类型的大小不同,为什么?枚举类型的声明是否会导致gcc将其视为signed int
?此功能会导致我的项目出现问题,例如,一个枚举类型的大小在" file_1.c"中为1,但在" file_2.c&#34中它的大小为4 ;。
我的测试代码:
enum foo foo_test(void);
enum foo {
FOO_0
};
enum bar {
BAR_0
};
int main(int argc, char **argv)
{
printf("sizeof(enum foo) %d, sizeof(enum bar) %d\n", sizeof(enum foo), sizeof(enum bar));
return 0;
}
当我在嵌入式项目中使用arm-none-eabi-gcc v4.9.3编译它时
sizeof(enum foo) 4, sizeof(enum bar) 1
。当我在Windows中用gcc v4.8.3编译它时
gcc -Wall -o sizeofTest.exe sizeofTest.c
进行编译
sizeof(enum foo) 4, sizeof(enum bar) 4
。gcc -Wall -fshort-enums -o sizeofTest.exe sizeofTest.c
进行编译
sizeof(enum foo) 4, sizeof(enum bar) 1
。答案 0 :(得分:6)
正如在c中询问特殊结果的问题一样常见,这里的原因是未定义的行为。 C11标准草案n1570 6.7.2.3p3:
- 醇>
表单的类型说明符
enum identifier
没有枚举器列表 仅在指定的类型完成后才会显示。
C11 6.7.2.2p4中的完整性:
- [...]枚举类型直到完成枚举器声明列表的}之后才完成,之后完成。
醇>
由于违反约束部分中的 ,符合标准的编译器必须输出诊断消息 - 但默认情况下GCC不是符合要求的实现,除非您提出要求是-pedantic
:
ISO C forbids forward references to ‘enum’ types [-Werror=pedantic] enum foo foo_test(void); ^
现在,似乎那里的编译器使用任何类型的最短可能的枚举。由于您在之前使用了enum foo
,实际上已经定义了其中的内容,因此编译器必须求助于int
类型,否则使用char
。它可以用-fshort-enums
复制。您的程序会打印4 1
,而此程序会在我的gcc上打印1 1
-fshort-enums
。
#include <stdio.h>
enum foo {
FOO_0
};
enum foo foo_test(void);
enum bar {
BAR_0
};
int main(int argc, char **argv)
{
printf("sizeof(enum foo) %zu, sizeof(enum bar) %zu\n",
sizeof(enum foo), sizeof(enum bar));
return 0;
}
答案 1 :(得分:4)
首先,修复代码中的未定义行为。 sizeof
表达式类型的正确格式说明符为%zu
。
C中的枚举器的支持类型可以是char
,int
或unsigned
。只要能够存储所有枚举值,编译器就可以选择其中任何一个。
因此值为1是可行的(因为sizeof(char)
总是1),并且您已经要求某些编译器挤压enum
支持类型。
对于int
的支持类型似乎选择了foo
这一事实,我认为,在您定义它之前引用enum foo
,以及您的友好C编译器正在使用某种隐式int
。这种隐式声明不再是标准C,而且您的代码不是严格可移植的。
答案 2 :(得分:2)
这是未定义的行为。
您必须使用%zu
将printf()
格式化为size_t
类型的值。
如果值的大小与int
的大小不同,printf()
中的代码将误读varargs-argument并错误地了解其值(va_arg(args, int);
而不是va_arg(args, size_t);
TextView tv = view.findViewbyId(R.id.textView);
。
答案 3 :(得分:-1)
答案其实很简单。
由于函数原型返回枚举类型,编译器将其假定为int并且其大小与硬件相关(在您的情况下为4个字节)它是为了优化目的而完成的。对于另一个,存储在尽可能小的数据类型中。 (可能使用-Os optimization和/或-shshort-enums)
对于具有真实编程经验的编码人员来说,这种行为是众所周知的,如果你想让它们保持简短,这就是没有将函数声明为返回枚举的原因。
对于C标准狂热分子uint8_t foo();
和return FOO_0;
可能是不可接受的,但编程是一门真实的,现实的和实用的科学。