1

In C11 (and later) integer constant expression shall only have operands that are, in particular:

floating constants that are the immediate operands of casts

The following code:

int a[ A > B ? 16 : 32 ];

when A and B are floating constants is invalid in 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]

but valid in C++:

$ echo '#include "t576.h"' | clang++ -std=c++11 -pedantic -Wall -Wextra -DA=1.0 -DB=2.0 -c -xc++ -
<nothing>

What is the origin / rationale of this requirement?

Extra question: In the future C standard revisions will it be useful to remove this requirement?

pmor
  • 5,392
  • 4
  • 17
  • 36
  • Are the floating point values `A` or `B` "the immediate operands of casts"? That would be no. – Andrew Henle Jan 14 '22 at 10:46
  • How exactly do you have A and B defined? I tested it as `const float A = 0.6f; const float B = 0.65f; int a[ A > B ? 16 : 32 ];` in C11 and it behaves as expected. – martorad Jan 14 '22 at 10:51
  • 1
    @martorad: In C language, the const qualifier does not magically change a variable into a compile time constant. Only `#define` can be used to define symbolic constants. Said differently you are defining a VLA... – Serge Ballesta Jan 14 '22 at 11:12
  • @SergeBallesta, indeed, that's my bad. That said, having both A and B initialized with `#define` also works in C11. Like you mentioned, though, without knowing OP's definition, we're left guessing. – martorad Jan 14 '22 at 11:17
  • @LanguageLawyer Does that boil down to floating point constants or variables though? – Lundin Jan 14 '22 at 11:24
  • @Lundin https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-d-macro https://gcc.gnu.org/onlinedocs/gcc/Preprocessor-Options.html – Language Lawyer Jan 14 '22 at 11:27
  • @LanguageLawyer: My bad. I seldom use command line constant definitions and forgot to examine the compilation command. – Serge Ballesta Jan 14 '22 at 11:34
  • @martorad See description: `-DA=1.0 -DB=2.0`. – pmor Jan 15 '22 at 09:58

2 Answers2

5

What is the origin / rationale of this requirement?

It means C compilers are not required to be able to execute floating-point arithmetic within the compiler. When compiling for a target platform different from the compiler host platform, replicating the exact behavior of the target floating-point operations can require a lot of work. (This was especially so prior to widespread adoption of the IEEE 754 standard for floating-point arithmetic.)

To implement floating-point semantics in a C program, the compiler only has to be able to convert the constants in source code to the target floating-point format and take the integer portion of them (in a cast). It does not have to be able to perform general arithmetic operations on them. Without this requirement, the compiler would have to reproduce the floating-point arithmetic operations of the target platform. So, if a program uses floating-point arithmetic, the compiler can implement that just by generating instructions to do the arithmetic; it does not have to do the arithmetic itself. This is also true for arithmetic constant expressions, which can be used as initializers: The compiler is not strictly required by the C standard to compute the value of the initializer. It can generate instructions that compute the value when the program starts running (for initialization of static objects) or when needed (for initialization of automatic objects).

In contrast, integer constant expressions can be used in places where the compiler needs the value, such as the width of a bit-field. So the compiler must be able to compute the value itself. If it were required to be able to do floating-point arithmetic to get the value, this would add considerable burden to writing some compilers.

Extra question: In the future C standard revisions will it be useful to remove this requirement?

Removing it will provide some opportunity for C program writers to use additional constant expressions and will require C compiler writers to do more work. The value of these things is subjective.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Floating point is oddly not an optional feature of C however. Not even for freestanding implementations. And it would be a very strange system if the cross-compiler isn't capable of performing float calculations, but the target is. – Lundin Jan 14 '22 at 11:50
  • 1
    @Lundin: The issue is not *per se* that the compiler might not be able to perform floating-point operations at all, although that is a possibility, but that the compiler might not be able to easily to perform the same floating-point computations as the target, matching the floating-point base, precision, rounding, and other behaviors, since there may be a mismatch between the target floating-point semantics and the compiler host’s floating-point semantics. – Eric Postpischil Jan 14 '22 at 12:03
  • Re: "mismatch": one [example](https://stackoverflow.com/q/64617357/1778275). However, despite of a potential mismatch, floating-point arithmetic is allowed in initializers. – pmor Jan 14 '22 at 16:40
  • Re: "C compilers are not required to be able to execute floating-point arithmetic within the compiler": consequence: code `enum { x = (int)-1.0 };` is invalid in C (but valid in C++). – pmor Jan 31 '22 at 14:01
1

The rationale is common sense: they don't want to allow users to declare an array of some 3.1415 items - the array size needs to be an integer, obviously.

For many operators in C, the usual arithmetic conversions would turn the end result into floating point whenever a floating point operand is present. In case of ?: specifically that doesn't happen, since the result is the 2nd or 3rd operand. Also the > operator does always return int so it doesn't really apply there either.

If you don't immediately cast floating point operands to an integer type, as told in the definition of an integer constant expression that you quote, then it will become an arithmetic constant expression instead, which is a broader term.

So you can do this:

int a[ (int)1.0 > (int)2.0 ? 16 : 32 ]; // compliant

But you can't do this:

int a[ 1.0 > 2.0 ? 16 : 32 ]; // not compliant

Consider int a[ (int)1.0 > (int)2.0 ? 16.0 : 32 ]; (not compliant either). Here the condition always evaluates as false. We should get size 32, but because of the special implicit conversion rules of ?: the 2nd and 3rd operands are balanced per the usual arithmetic conversions, so we end up with 32.0 of type double. And if that in turn would lead to a floating point number that cannot be exactly represented, we would get a floating point array size.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    I think this answer misses the point of the question, which I read as: *"Why doesn't C allow intermediate floating point steps within integer constant expression, when C++ demonstrates that it could be possible to have them?"* I believe that array size or conditional operator are not the core of the question, but were used only to demonstrate it. – user694733 Jan 14 '22 at 12:55