To my surprise, this code compiles with GCC 11.4.0 and i
becomes 0:
#include <stdio.h>
int main( int argc, char *argv[] )
{
int i = 1i;
printf( "i = %d\n", i );
return 0;
}
I tried googling for the suffix i
, but without success. In every description I've found only the usual ones are mentioned (e.g., in the answers to that Stack Overflow question).
I've also tried with all lower characters and other integer values and found that it's the same behaviour with j
, and the value of my variable was always 0
. With other suffixes like a, b, etc., it wouldn't compile.
So what is it that I've been stumbled upon? And is there a way to prevent GCC from compiling that or at least have some kind of diagnostics? In the 'real-world source' this happened because of a simple typo and of course resulted in run time errors.
From GNU docs:
The simple way to write an imaginary-number constant is to attach the suffix ‘i’ or ‘I’, or ‘j’ or ‘J’, to an integer or floating-point constant. For example,
2.5fi
has type_Complex float
and3i
has type_Complex int
. The four alternative suffix letters are all equivalent...Standard C doesn’t support suffixing with ‘i’ or ‘j’.
So we can conclude:
ISO C Standard doesn't support i
, I
, j
, or J
suffixes. These suffixes are a GCC extension.
i
, j
, I
, and J
are equivalent.
Attaching any of the aforementioned suffixes to an integer or floating-point constant makes it an imaginary-number constant.
This GNU extension is also supported by Clang.
Compiling with -pedantic-errors
fails:
$ gcc c.c -pedantic-errors -o c
c.c: In function 'main':
c.c:5:17: error: imaginary constants are a GCC extension
5 | int i = 1i;
| ^~
$ clang c.c -pedantic-errors -o c
c.c:5:17: error: imaginary constants are a GNU extension [-Werror,-Wgnu-imaginary-constant]
int i = 1i;
^
1 error generated.
See also: What compiler options are recommended for beginners learning C?.
As of why i
became 0:
From section 6.3.1.7 of the ISO C Standard regarding Real and Complex conversions:
When a value of real type is converted to a complex type, the real part of the complex result value is determined by the rules of conversion to the corresponding real type and the imaginary part of the complex result value is a positive zero or an unsigned zero.
When a value of complex type is converted to a real type, the imaginary part of the complex value is discarded and the value of the real part is converted according to the conversion rules for the corresponding real type.
So when you assign 1i
to an int
, it becomes 0
because the that's the real part of 1i
, and the imaginary part is discarded.
ISO C does support I
for the imaginary part (although it is not a suffix, and is a constant and requires multiplication; like 3 + 4*I
), although support for complex.h
and complex numbers is optional for the compiler. The compiler may define __STDC_NO_COMPLEX__
if it does not support such.
From the ISO C Standard, 7.3.1 Introduction:
....
The macro
I
expands to either_Imaginary_I
or_Complex_I
. If_Imaginary_I
is not defined, I shall expand to_Complex_I
.¶7 Notwithstanding the provisions of 7.1.3, a program may undefine and perhaps then redefine the macros complex, imaginary, and I.
As of the suffixes a
, b
, et cetera, neither the ISO C Standard, nor the GNU C Standard has support for any such thing.
The gcc compiler unfortunately comes in "safety hazard mode" by default, since it is by default using a non-standard superset of the C language called GNU C (-std=gnu17
).
The GNU C language contains a lot of things that are in direct conflict with conforming C. It also contains lots of non-standard alternative features to things that already exist in standard, such as imaginary number support, flexible array members, alignment specifiers etc etc. In GNU mode, gcc is happy to let such things pass silently, even if they are non-conforming C or breaks a conforming C program.
In this case you happened to stumble upon the GNU extension for complex numbers where i
is a non-standard imaginary part suffix. This is a different one than the complex number implementation introduced by the C99 standard.
If you care about C language conformance, you should always compile with -std=c17 -pedantic-errors
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With