0

In the example below, the initializer is one element smaller than the static array. In this case avr-g++-6.3 as well as avr-g++-7.0 produces code with no elements in the data-section (initializer). That is what I would expect.

#include <stdint.h>

volatile uint8_t x = 0;
volatile uint8_t y = 0;

int main() {
    constexpr uint8_t l[4] = {0, 1, 2};
    y = l[x];
    while(true) {}
}

But, if I change the code to

#include <stdint.h>

volatile uint8_t x = 0;
volatile uint8_t y = 0;

int main() {
    constexpr uint8_t l[3] = {0, 1, 2};
    y = l[x];
    while(true) {}
}

(here the static array length is as smal as possible)

both compiler generate a data section of 4 bytes. Thats very(!) surpising for me. The effect is reproducible with all kinds of static arrays as well as with std::array<>, if the size of the array is the same as the number of initializers.

Whats going on here?

Heres the assembler output for the first case:

    .file   "bm10a.cc"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
    .section    .text.startup,"ax",@progbits
.global main
    .type   main, @function
main:
    push r28
    push r29
    rcall .
    rcall .
    in r28,__SP_L__
    in r29,__SP_H__
/* prologue: function */
/* frame size = 4 */
/* stack size = 6 */
.L__stack_usage = 6
    std Y+1,__zero_reg__
    std Y+2,__zero_reg__
    std Y+3,__zero_reg__
    std Y+4,__zero_reg__
    ldi r24,lo8(1)
    std Y+2,r24
    ldi r24,lo8(2)
    std Y+3,r24
    lds r30,x
    add r30,r28
    mov r31,r29
    adc r31,__zero_reg__
    ldd r24,Z+1
    sts y,r24
.L2:
    rjmp .L2
    .size   main, .-main
.global y
    .section .bss
    .type   y, @object
    .size   y, 1
y:
    .zero   1
.global x
    .type   x, @object
    .size   x, 1
x:
    .zero   1
    .ident  "GCC: (GNU) 7.0.1 20170218 (experimental)"
.global __do_clear_bss

And here for the second case:

    .file   "bm10a.cc"
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__SREG__ = 0x3f
__tmp_reg__ = 0
__zero_reg__ = 1
    .section    .rodata
.LC0:
    .byte   0
    .byte   1
    .byte   2
    .section    .text.startup,"ax",@progbits
.global main
    .type   main, @function
main:
    push r28
    push r29
    rcall .
    push __zero_reg__
    in r28,__SP_L__
    in r29,__SP_H__
/* prologue: function */
/* frame size = 3 */
/* stack size = 5 */
.L__stack_usage = 5
    lds r24,.LC0
    lds r25,.LC0+1
    lds r26,.LC0+2
    std Y+1,r24
    std Y+2,r25
    std Y+3,r26
    lds r30,x
    add r30,r28
    mov r31,r29
    adc r31,__zero_reg__
    ldd r24,Z+1
    sts y,r24
.L2:
    rjmp .L2
    .size   main, .-main
.global y
    .section .bss
    .type   y, @object
    .size   y, 1
y:
    .zero   1
.global x
    .type   x, @object
    .size   x, 1
x:
    .zero   1
    .ident  "GCC: (GNU) 7.0.1 20170218 (experimental)"
.global __do_copy_data
.global __do_clear_bss
wimalopaan
  • 4,838
  • 1
  • 21
  • 39
  • [OT]: `while(true) {}` is UB. – Jarod42 Mar 01 '17 at 12:55
  • Really? Can you elaborate that? If so, most µC Code would be UB ... – wimalopaan Mar 01 '17 at 12:59
  • Look at [is-this-infinite-recursion-ub](http://stackoverflow.com/questions/5905155/is-this-infinite-recursion-ub) – Jarod42 Mar 01 '17 at 13:05
  • It looks like arrays with incomplete initialization are handled differently in the compiler. A third test could be how `constexpr uint8_t l[] = {0, 1, 2};` is compiled. An exact answer you may find in the gcc source code. (I once looked into gcc source code to get hints for some compiler construction issues but that was hard to read... (for me)) – Scheff's Cat Mar 01 '17 at 13:05
  • Yes, the different types of initialization are handled differently. But: since it is constexpr it shouldn't use any RAM at all! – wimalopaan Mar 01 '17 at 13:14
  • The `constexpr uint8_t l[] = {0, 1, 2};` is handled like full initialization (with usage of data-segment). – wimalopaan Mar 01 '17 at 13:18

0 Answers0