Advancement in evaluating constant integer expressions in preprocessor directives - GCC

NOTE. See my changes below.

ORIGINAL QUESTION:

There was some curious behavior that I can’t put up with:

#if -5 < 0
#warning Good, -5 is less than 0.
#else
#error BAD, -5 is NOT less than 0.
#endif

#if -(5u) < 0
#warning Good, -(5u) is less than 0.
#else
#error BAD, -(5u) is less than 0.
#endif

#if -5 < 0u
#warning Good, -5 is less than 0u.
#else
#error BAD, -5 is less than 0u.
#endif

When compiling:

$ gcc -Wall -o pp_test.elf pp_test.c
pp_test.c:2:6: warning: #warning Good, -5 is less than 0.
pp_test.c:10:6: error: #error BAD, -(5u) is less than 0.
pp_test.c:13:9: **warning: the left operand of "<" changes sign when promoted**
pp_test.c:16:6: error: #error BAD, -5 is less than 0u.

This suggests that the preprocessor adheres to type promotion rules when evaluating constant integer expressions. Namely, when the operator has mixed-sign operands, the signed operand is replaced with the unsigned operand. The opposite (in general) is true in C.

I cannot find anything in the literature to support this, but is it possible (probably?) That I am not thorough enough. Did I miss something? Is this behavior right?

, , #if #elif, , , .. C.


EDIT:. Sourav Ghosh, , , L LL. , , . :

#if -5LL < 0L
#warning Good, -5LL is less than 0L.
#else
#error BAD, -5LL is NOT less than 0L.
#endif

#if -(5uLL) < 0L
#warning Good, -(5uLL) is less than 0L.
#else
#error BAD, -(5uLL) is less than 0L.
#endif

#if -5LL < 0uL
#warning Good, -5LL is less than 0uL.
#else
#error BAD, -5LL is less than 0uL.
#endif

:

$ gcc -Wall -o pp_test.elf pp_test.c
pp_test.c:2:6: warning: #warning Good, -5LL is less than 0L.
pp_test.c:10:6: error: #error BAD, -(5uLL) is less than 0L.
pp_test.c:13:9: warning: the left operand of "<" changes sign when promoted
pp_test.c:16:6: error: #error BAD, -5LL is less than 0uL.

, -, 6.3.1.8, , Sourav Ghosh ( ):

, , .

, , -5LL , , 0uL, , (signed long long) (unsigned long). , .

https://gcc.gnu.org/onlinedocs/gcc-3.0.2/cpp_4.html ( ):

. , ; , GCC, 64 . , . , `#if ', ; .

, " , ", , , " " . , -5 -5L , -5LL, 0u 0uL , 0uLL. , Sourav Ghosh, .

, , , , . , ?


№ 2: , - , ( Optiboot).

#ifndef BAUD_RATE
#if F_CPU >= 8000000L
#define BAUD_RATE   115200L
#elif F_CPU >= 1000000L
#define BAUD_RATE   9600L
#elif F_CPU >= 128000L
#define BAUD_RATE   4800L
#else
#define BAUD_RATE 1200L
#endif
#endif

#ifndef UART
#define UART 0
#endif

#define BAUD_SETTING (( (F_CPU + BAUD_RATE * 4L) / ((BAUD_RATE * 8L))) - 1 )
#define BAUD_ACTUAL (F_CPU/(8 * ((BAUD_SETTING)+1)))
#define BAUD_ERROR (( 100*(BAUD_ACTUAL - BAUD_RATE) ) / BAUD_RATE)

#if BAUD_ERROR >= 5
#error BAUD_RATE error greater than 5%
#elif (BAUD_ERROR + 5) <= 0
#error BAUD_RATE error greater than -5%
#elif BAUD_ERROR >= 2
#warning BAUD_RATE error greater than 2%
#elif (BAUD_ERROR + 2) <= 0
#warning BAUD_RATE error greater than -2%
#endif

volatile long long int baud_setting = BAUD_SETTING;
volatile long long int baud_actual = BAUD_ACTUAL;
volatile long long int baud_error = BAUD_ERROR;

void foo(void) {
  baud_setting = BAUD_SETTING;
  baud_actual = BAUD_ACTUAL;
  baud_error = BAUD_ERROR;
}

AVR:

$ avr-gcc -Wall -c -g -save-temps -o optiboot_pp_test.elf -DF_CPU=8000000L optiboot_pp_test.c

, F_CPU .

optiboot_pp_test.c:28:6: warning: #warning BAUD_RATE error greater than -2% [-Wcpp]
     #warning BAUD_RATE error greater than -2%

, . :

      baud_setting = BAUD_SETTING;
   8:   88 e0           ldi     r24, 0x08       ; 8
   a:   90 e0           ldi     r25, 0x00       ; 0
   c:   a0 e0           ldi     r26, 0x00       ; 0
   e:   b0 e0           ldi     r27, 0x00       ; 0
  10:   80 93 00 00     sts     0x0000, r24
  14:   90 93 00 00     sts     0x0000, r25
  18:   a0 93 00 00     sts     0x0000, r26
  1c:   b0 93 00 00     sts     0x0000, r27
      baud_actual = BAUD_ACTUAL;
  20:   87 e0           ldi     r24, 0x07       ; 7
  22:   92 eb           ldi     r25, 0xB2       ; 178
  24:   a1 e0           ldi     r26, 0x01       ; 1
  26:   b0 e0           ldi     r27, 0x00       ; 0
  28:   80 93 00 00     sts     0x0000, r24
  2c:   90 93 00 00     sts     0x0000, r25
  30:   a0 93 00 00     sts     0x0000, r26
  34:   b0 93 00 00     sts     0x0000, r27
      baud_error = BAUD_ERROR;
  38:   8d ef           ldi     r24, 0xFD       ; 253
  3a:   9f ef           ldi     r25, 0xFF       ; 255
  3c:   af ef           ldi     r26, 0xFF       ; 255
  3e:   bf ef           ldi     r27, 0xFF       ; 255
  40:   80 93 00 00     sts     0x0000, r24
  44:   90 93 00 00     sts     0x0000, r25
  48:   a0 93 00 00     sts     0x0000, r26
  4c:   b0 93 00 00     sts     0x0000, r27

... , . , baud_setting 8, baud_actual 111111, baud_error -3.

F_CPU, ( ):

$ avr-gcc -Wall -c -g -save-temps -o optiboot_pp_test.elf -DF_CPU=8000000UL optiboot_pp_test.c 
optiboot_pp_test.c:22:6: error: #error BAUD_RATE error greater than 5%
     #error BAUD_RATE error greater than 5%

.

, , F_CPU.

, , , .

, , GCC ( ).

, C , , . - , , , L LL, LL , , 6.3.1.8, GCC. GCC, , " , ".

( ) , , , , . , , , , . , . , , , , ( ) , .

- - , GCC, .


№ 3: . , .

- - , , GCC, .

6.10.1:

  1. , , intmax_t uintmax_t, < stdint.h > .

, , .

+4
3

( ) C11, §6.3.1.8.

, , .

, .

, , , , .

+3

, .

, - , . , . .

6.3.1.3p2, 2s ( , ) , () , .

, -Wconversions (gcc), .

+1

C , , . , , C:

, [] 6.6.

(C99, 6.10.1)

6.6 C , ( 11),

The semantic rules for evaluating a constant expression are the same as for mutable expressions.

Thus, the rules of assessment are the same in all directions. In particular, the same “ordinary arithmetic transformations” are applied in each case when the types of operands of a binary operator differ. Other answers speak for these details.

+1
source

Source: https://habr.com/ru/post/1598926/


All Articles