什么是错误使用ARM C编译器选项“Enum container always int”的示例?

时间:2015-10-27 10:43:05

标签: c arm compiler-options

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)

函数调用未正确格式化浮点数。

通过使用用作堆栈的内存的右对齐,几乎可以解决这个问题。 “几乎”修复,因为数组的内容没问题,但小数点有错误的字符。删除上面提到的编译器选项修复了问题。所以问题是这个编译器选项完全是什么以及它的错误使用是什么?

3 个答案:

答案 0 :(得分:2)

我假设你指的是这个选项:

  

枚举容器始终为int

     

选择此选项可强制所有枚举存储在整数中。默认情况下,编译器使用可以保存枚举中所有值的最小数据类型。

在C中,用于枚举类型的类型是实现定义的(但enum常量始终是int):它是一个整数类型,可以表示所有enum常量。

如果您将枚举类型的类型设置为int,我可以想到两个问题:

1)如果您的程序依赖于enumint的事实(例如假设sizeofsizeof (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结构。将enumchar更改为int(或相反)会更改堆栈变量的对齐方式,从而使浮动对齐。 (sprintf()的第三个变量float几乎肯定会最终被传递到堆栈上)

ARM要求堆栈为8字节对齐。最好将其声明为uint64_t(并且绝对不在__packed结构中),因此它的对齐始终是正确的。