I have been trying to define a static array with size that should be known at compile time (it's a constant expression). It appears that gcc cannot determine the size of the array when it contains a floating point constant (and I get "storage size of ... isn’t constant").
我一直在尝试定义一个大小应该在编译时知道的静态数组(它是一个常量表达式)。看来gcc在包含浮点常量时无法确定数组的大小(我得到“存储大小为......不是常数”)。
Here is a minimal example:
这是一个最小的例子:
int main(void)
{
static int foo[(unsigned)(2 / 0.5)];
return 0;
}
What is the reason for this behavior?
这种行为的原因是什么?
EDIT
I already have the answer I needed. I still don't understand the rationale behind not allowing that kind of expressions, but this is a separate question. I'll explain for the curious how I arrived at the problem.
我已经有了我需要的答案。我仍然不明白不允许这种表达背后的理由,但这是一个单独的问题。我将解释好奇我是如何解决这个问题的。
It's about a game I'm writing as an excercise. Units move on a battlefield and I have divided the movement in steps. I have to remember the position of each unit on each step so that I can display animation later. The number of steps is chosen so that it ensures there will be a step on which units are close enough to fight each other but not so close as to collide. Here are the relevant pieces of code:
这是一个我正在写作游戏的游戏。单位在战场上移动,我已经分阶段划分了运动。我必须记住每个步骤中每个单元的位置,以便我以后可以显示动画。选择步数,以确保有一个步骤,使得单位足够接近以相互对抗但不会碰到碰撞。以下是相关的代码:
#define UNIT_SPEED_LIMIT 12
#define DISTANCE_MELEE 0.25
#define MOVEMENT_STEPS (unsigned)(2 * UNIT_SPEED_LIMIT / DISTANCE_MELEE)
struct position (*movements)[MOVEMENT_STEPS + 1];
Defining DISTANCE_MELEE
(maximum distance at which close combat is possible) and using it to calculate the number of steps seems to be the natural way to proceed (more so because I use this constant in multiple contexts). Since I cannot define movements
this way, I have to invent a concept like "number of steps for a single unit of distance" and use multiplication by int
instead of division by double
. I want to avoid dynamic memory allocation in order to keep the code simple.
定义DISTANCE_MELEE(可以进行近战的最大距离)并使用它来计算步数似乎是继续进行的自然方式(更多是因为我在多个上下文中使用此常量)。由于我无法通过这种方式定义运动,因此我必须发明一个概念,例如“单个距离单位的步数”,并使用乘法乘以而不是乘以双。我想避免动态内存分配,以保持代码简单。
2 个解决方案
#1
5
According to the publicly available C99 draft standard n1256, the syntax for array declaration is described by
根据公开的C99草案标准n1256,数组声明的语法由
6.7.5.2 Array declarators
6.7.5.2数组声明符
2
An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope. If an identifier is declared to be an object with static storage duration, it shall not have a variable length array type.
具有可变修改类型的普通标识符(如6.2.3中所定义)应具有块范围和无链接或函数原型范围。如果标识符被声明为具有静态存储持续时间的对象,则它不应具有可变长度数组类型。
4
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; 124) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
如果大小不存在,则数组类型是不完整类型。如果大小是*而不是表达式,则数组类型是未指定大小的可变长度数组类型,只能在具有函数原型范围的声明中使用; 124)这样的阵列仍然是完整的类型。如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型;否则,数组类型是可变长度数组类型。
So the expression in the []
must be an integer constant expression for the array to be declarable with static
storage duration. The standard has this to say about integer constant expressions:
因此,[]中的表达式必须是可以使用静态存储持续时间声明的数组的整数常量表达式。关于整数常量表达式,标准有这个说法:
6.6 Constant expressions
6.6常量表达式
6
An integer constant expression 99) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.
整数常量表达式99)应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,以及作为强制转换的直接操作数的浮点常量。整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof运算符的操作数的一部分。
Unfortunately, (unsigned)(2 / 0.5)
does not apply the cast immediately to a floating-point constant, but rather to an arithmetic constant expression. This does not constitute an integer constant expression, and is thus not permissible as the size of an array with static
storage duration.
不幸的是,(无符号)(2 / 0.5)不会立即将强制转换应用于浮点常量,而是应用于算术常量表达式。这不构成整数常量表达式,因此不允许作为具有静态存储持续时间的阵列的大小。
#2
1
OP's primary question is well answer here.
OP的主要问题在这里是很好的答案。
To address OP's higher level problem of how to use values like 0.5 or 0.25 in pre-processing, use fractional arithmetic:
要解决OP在预处理中如何使用0.5或0.25等值的更高级别问题,请使用小数算术:
#define UNIT_SPEED_LIMIT 12
// #define DISTANCE_MELEE 0.25
// use 25/100 or 1/4 or ...
#define DISTANCE_MELEE_N 1
#define DISTANCE_MELEE_D 4
// #define MOVEMENT_STEPS (unsigned)(2 * UNIT_SPEED_LIMIT / DISTANCE_MELEE)
#define MOVEMENT_STEPS (2u * UNIT_SPEED_LIMIT * DISTANCE_MELEE_D / DISTANCE_MELEE_N)
struct position (*movements)[MOVEMENT_STEPS + 1];
#1
5
According to the publicly available C99 draft standard n1256, the syntax for array declaration is described by
根据公开的C99草案标准n1256,数组声明的语法由
6.7.5.2 Array declarators
6.7.5.2数组声明符
2
An ordinary identifier (as defined in 6.2.3) that has a variably modified type shall have either block scope and no linkage or function prototype scope. If an identifier is declared to be an object with static storage duration, it shall not have a variable length array type.
具有可变修改类型的普通标识符(如6.2.3中所定义)应具有块范围和无链接或函数原型范围。如果标识符被声明为具有静态存储持续时间的对象,则它不应具有可变长度数组类型。
4
If the size is not present, the array type is an incomplete type. If the size is * instead of being an expression, the array type is a variable length array type of unspecified size, which can only be used in declarations with function prototype scope; 124) such arrays are nonetheless complete types. If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.
如果大小不存在,则数组类型是不完整类型。如果大小是*而不是表达式,则数组类型是未指定大小的可变长度数组类型,只能在具有函数原型范围的声明中使用; 124)这样的阵列仍然是完整的类型。如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型;否则,数组类型是可变长度数组类型。
So the expression in the []
must be an integer constant expression for the array to be declarable with static
storage duration. The standard has this to say about integer constant expressions:
因此,[]中的表达式必须是可以使用静态存储持续时间声明的数组的整数常量表达式。关于整数常量表达式,标准有这个说法:
6.6 Constant expressions
6.6常量表达式
6
An integer constant expression 99) shall have integer type and shall only have operands that are integer constants, enumeration constants, character constants, sizeof expressions whose results are integer constants, and floating constants that are the immediate operands of casts. Cast operators in an integer constant expression shall only convert arithmetic types to integer types, except as part of an operand to the sizeof operator.
整数常量表达式99)应具有整数类型,并且只能具有整数常量的操作数,枚举常量,字符常量,结果为整数常量的sizeof表达式,以及作为强制转换的直接操作数的浮点常量。整数常量表达式中的转换运算符只能将算术类型转换为整数类型,除非作为sizeof运算符的操作数的一部分。
Unfortunately, (unsigned)(2 / 0.5)
does not apply the cast immediately to a floating-point constant, but rather to an arithmetic constant expression. This does not constitute an integer constant expression, and is thus not permissible as the size of an array with static
storage duration.
不幸的是,(无符号)(2 / 0.5)不会立即将强制转换应用于浮点常量,而是应用于算术常量表达式。这不构成整数常量表达式,因此不允许作为具有静态存储持续时间的阵列的大小。
#2
1
OP's primary question is well answer here.
OP的主要问题在这里是很好的答案。
To address OP's higher level problem of how to use values like 0.5 or 0.25 in pre-processing, use fractional arithmetic:
要解决OP在预处理中如何使用0.5或0.25等值的更高级别问题,请使用小数算术:
#define UNIT_SPEED_LIMIT 12
// #define DISTANCE_MELEE 0.25
// use 25/100 or 1/4 or ...
#define DISTANCE_MELEE_N 1
#define DISTANCE_MELEE_D 4
// #define MOVEMENT_STEPS (unsigned)(2 * UNIT_SPEED_LIMIT / DISTANCE_MELEE)
#define MOVEMENT_STEPS (2u * UNIT_SPEED_LIMIT * DISTANCE_MELEE_D / DISTANCE_MELEE_N)
struct position (*movements)[MOVEMENT_STEPS + 1];