在http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0065d/Cihejcda.html中有一个选项和一个注释:
枚举容器始终为int
选择此选项可强制所有枚举存储在整数中。默认情况下,编译器使用可以保存枚举中所有值的最小数据类型。
注意
建议不要将此选项用于一般用途,并且ANSI兼容源不需要此选项。如果使用不当,此选项可能会导致生成的图像出错。
这种错误使用的C中有什么例子?
背景:
我正在用C开发一个嵌入式应用程序,删除这个编译器标志修复了一个错误(或只是另一个错误的症状)。错误是
sprintf(big_enought_char_array, "%4.1f", float_var)
函数调用未正确格式化浮点数。
通过使用用作堆栈的内存的右对齐,几乎可以解决这个问题。 “几乎”修复,因为数组的内容没问题,但小数点有错误的字符。删除上面提到的编译器选项修复了问题。所以问题是这个编译器选项完全是什么以及它的错误使用是什么?
答案 0 :(得分:2)
我假设你指的是这个选项:
枚举容器始终为int
选择此选项可强制所有枚举存储在整数中。默认情况下,编译器使用可以保存枚举中所有值的最小数据类型。
在C中,用于枚举类型的类型是实现定义的(但enum
常量始终是int
):它是一个整数类型,可以表示所有enum
常量。
如果您将枚举类型的类型设置为int
,我可以想到两个问题:
1)如果您的程序依赖于enum
为int
的事实(例如假设sizeof
与sizeof (int)
相同),则不可移植在其他系统上
2)如果您定义一个值大于INT_MAX
的常量(或int
无法表示的值),例如UINT_MAX
,则您的类型将无法表示保证C enum
代表它的地方。
关于sprintf
电话的具体问题,它似乎与此选项完全无关。您可能在调用之前调用了一些未定义的行为。
答案 1 :(得分:1)
这个编译器选项究竟是什么做的
嗯,通常你的平均enum
没有例如2³条目 - 在大多数情况下,它甚至没有256条。在这种情况下,C编译器通常可以自由地使用较短的值表示,例如:一个字节。
使用该标志将使所有enum
占用相同的int
大小(读取:字长)内存。这只是在几个非常特殊的情况下,显然,它会打破sprintf
;我认为这不是常见的事情,所以:您使用的libc
实施是什么?确保它没有明确禁止使用该标志,并在必要时提交错误报告。制作一个最小的测试用例来证明这个问题。
答案 2 :(得分:0)
以下是关于sprintf()
的猜测:
您的堆栈实际上被声明为char[]
数组,它是一些enum
个变量,或者是__packed
结构。将enum
从char
更改为int
(或相反)会更改堆栈变量的对齐方式,从而使浮动对齐。 (sprintf()
的第三个变量float
几乎肯定会最终被传递到堆栈上)
ARM要求堆栈为8字节对齐。最好将其声明为uint64_t
(并且绝对不在__packed
结构中),因此它的对齐始终是正确的。