Why is there now a difference between “{static const char a[]={…}” and “{const char a[]={…}”?

  • A+

Have a look at this tiny snippet of C code or C++ code on godbolt...

void b( char const *c);  void a(void) {    char const z[] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf, 0xa};     b(z); }  void c(void) {    static char const z[] = {0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf, 0xa};     b(z); } 

Earlier versions of gcc compiles both a() and c() to two instructions, load address of z, jump to b.

All modern compilers I tried "pessimise" a() to "make stack frame, copy z onto stack, call b, tear down stack frame, but leave c() as the two instruction simple version.

In effect nothing has changed, in practice modern compilers are now slower for this use case.....

Anybody have any idea why?


I expect the answer to be that the compiler does what you in your code specify should happen - there must be a function-local array of automatic storage that is not shared with other threads, that is to be passed into other functions. Previously the compiler could use the as-if rule to remove that and put it elsewhere as the language didn't have threads as a thing that existed in its model, but since threads are now present it has to ensure it does not accidentally cause false sharing with others. It could've probably made it thread-local, but that's worse than just function local.

Note that GCC never did the optimization, but Clang stopped doing so after 6.0.0. It might even be a Clang bug to have used this optimization.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: