为什么在整数常量表达式中使用浮点运算是无效的?
Why exactly using of a floating-point arithmetic in an integer constant expression is invalid?
在 C11(及更高版本)中,整型常量表达式只能有操作数,特别是:
floating constants that are the immediate operands of casts
以下代码:
int a[ A > B ? 16 : 32 ];
当 A
和 B
是浮动常量时在 C:
中无效
$ echo '#include "t576.h"' | clang -std=c11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc -
In file included from <stdin>:1:
./t576.h:1:5: warning: size of static array must be an integer constant expression [-Wpedantic]
但在 C++ 中有效:
$ echo '#include "t576.h"' | clang++ -std=c++11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc++ -
<nothing>
此要求的起源/理由是什么?
附加问题:在未来的C标准修订中,删除此要求是否有用?
基本原理是常识:他们不想让用户声明一个包含 3.1415 个项目的数组 - 数组大小 需要 显然是一个整数。
对于 C 中的许多运算符,只要存在浮点操作数,通常的算术转换会将最终结果转换为浮点数。在 ?:
的情况下,这不会发生,因为结果是第二个或第三个操作数。 >
运算符也总是 return int
所以它也并不真正适用于那里。
如果您不立即将浮点操作数转换为整数类型,如您引用的整数常量表达式的定义中所述,那么它将变成算术常量表达式 相反,这是一个更广泛的术语。
所以你可以这样做:
int a[ (int)1.0 > (int)2.0 ? 16 : 32 ]; // compliant
但是你不能这样做:
int a[ 1.0 > 2.0 ? 16 : 32 ]; // not compliant
考虑 int a[ (int)1.0 > (int)2.0 ? 16.0 : 32 ];
(也不合规)。这里的条件总是评估为假。我们应该得到大小 32,但是由于 ?:
的特殊隐式转换规则,第二个和第三个操作数根据通常的算术转换是平衡的,所以我们最终得到类型 double
的 32.0
.如果这反过来会导致无法精确表示的浮点数,我们将得到一个浮点数组大小。
What is the origin / rationale of this requirement?
这意味着 C 编译器不需要能够在编译器内执行浮点运算。当针对不同于编译器主机平台的目标平台进行编译时,复制目标浮点运算的确切行为可能需要大量工作。 (在广泛采用 IEEE 754 浮点运算标准之前尤其如此。)
要在 C 程序中实现浮点语义,编译器只需要能够将源代码中的常量转换为目标浮点格式并取其整数部分(在强制转换中)。它不必能够对它们执行一般的算术运算。如果没有这个要求,编译器将不得不重现目标平台的浮点算术运算。因此,如果一个程序使用浮点运算,编译器可以通过生成指令来执行运算来实现它;它不必自己进行算术运算。对于可用作初始化器的算术常量表达式也是如此:C 标准并不严格要求编译器计算初始化器的值。它可以在程序启动时生成计算值的指令运行(用于静态对象的初始化)或在需要时(用于自动对象的初始化)。
相比之下,整数常量表达式可以用在编译器需要值的地方,例如位域的宽度。所以编译器必须能够自己计算值。如果要求能够进行浮点运算来获取值,这将给编写一些编译器增加相当大的负担。
Extra question: In the future C standard revisions will it be useful to remove this requirement?
删除它将为 C 程序编写者提供一些使用额外常量表达式的机会,并要求 C 编译器编写者做更多的工作。这些东西的价值是主观的。
在 C11(及更高版本)中,整型常量表达式只能有操作数,特别是:
floating constants that are the immediate operands of casts
以下代码:
int a[ A > B ? 16 : 32 ];
当 A
和 B
是浮动常量时在 C:
$ echo '#include "t576.h"' | clang -std=c11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc -
In file included from <stdin>:1:
./t576.h:1:5: warning: size of static array must be an integer constant expression [-Wpedantic]
但在 C++ 中有效:
$ echo '#include "t576.h"' | clang++ -std=c++11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc++ -
<nothing>
此要求的起源/理由是什么?
附加问题:在未来的C标准修订中,删除此要求是否有用?
基本原理是常识:他们不想让用户声明一个包含 3.1415 个项目的数组 - 数组大小 需要 显然是一个整数。
对于 C 中的许多运算符,只要存在浮点操作数,通常的算术转换会将最终结果转换为浮点数。在 ?:
的情况下,这不会发生,因为结果是第二个或第三个操作数。 >
运算符也总是 return int
所以它也并不真正适用于那里。
如果您不立即将浮点操作数转换为整数类型,如您引用的整数常量表达式的定义中所述,那么它将变成算术常量表达式 相反,这是一个更广泛的术语。
所以你可以这样做:
int a[ (int)1.0 > (int)2.0 ? 16 : 32 ]; // compliant
但是你不能这样做:
int a[ 1.0 > 2.0 ? 16 : 32 ]; // not compliant
考虑 int a[ (int)1.0 > (int)2.0 ? 16.0 : 32 ];
(也不合规)。这里的条件总是评估为假。我们应该得到大小 32,但是由于 ?:
的特殊隐式转换规则,第二个和第三个操作数根据通常的算术转换是平衡的,所以我们最终得到类型 double
的 32.0
.如果这反过来会导致无法精确表示的浮点数,我们将得到一个浮点数组大小。
What is the origin / rationale of this requirement?
这意味着 C 编译器不需要能够在编译器内执行浮点运算。当针对不同于编译器主机平台的目标平台进行编译时,复制目标浮点运算的确切行为可能需要大量工作。 (在广泛采用 IEEE 754 浮点运算标准之前尤其如此。)
要在 C 程序中实现浮点语义,编译器只需要能够将源代码中的常量转换为目标浮点格式并取其整数部分(在强制转换中)。它不必能够对它们执行一般的算术运算。如果没有这个要求,编译器将不得不重现目标平台的浮点算术运算。因此,如果一个程序使用浮点运算,编译器可以通过生成指令来执行运算来实现它;它不必自己进行算术运算。对于可用作初始化器的算术常量表达式也是如此:C 标准并不严格要求编译器计算初始化器的值。它可以在程序启动时生成计算值的指令运行(用于静态对象的初始化)或在需要时(用于自动对象的初始化)。
相比之下,整数常量表达式可以用在编译器需要值的地方,例如位域的宽度。所以编译器必须能够自己计算值。如果要求能够进行浮点运算来获取值,这将给编写一些编译器增加相当大的负担。
Extra question: In the future C standard revisions will it be useful to remove this requirement?
删除它将为 C 程序编写者提供一些使用额外常量表达式的机会,并要求 C 编译器编写者做更多的工作。这些东西的价值是主观的。