Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is there now a difference between "{static const char a[]={...}" and "{const char a[]={...}"?

Tags:

c++

c

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?

like image 703
John Carter Avatar asked Oct 30 '18 02:10

John Carter


People also ask

What is the difference between char const and const char?

The difference is that const char * is a pointer to a const char , while char * const is a constant pointer to a char . The first, the value being pointed to can't be changed but the pointer can be. The second, the value being pointed at can change but the pointer can't (similar to a reference).

What is the difference between char const * p and const char * p in C language?

C. NOTE: There is no difference between const char *p and char const *p as both are pointer to a const char and position of '*'(asterik) is also same.

Why do we use const char?

If you don't have the choice, using const char* gives a guarantee to the user that you won't change his data especially if it was a string literal where modifying one is undefined behavior. Show activity on this post. By using const you're promising your user that you won't change the string being passed in.

What does const char * const mean?

In C programming language, *p represents the value stored in a pointer and p represents the address of the value, is referred as a pointer. const char* and char const* says that the pointer can point to a constant char and value of char pointed by this pointer cannot be changed.


2 Answers

C++ has the following rule:

Unless an object is a bit-field or a subobject of zero size, the address of that object is the address of the first byte it occupies. Two objects with overlapping lifetimes that are not bit-fields may have the same address if one is nested within the other, or if at least one is a subobject of zero size and they are of different types; otherwise, they have distinct addresses and occupy disjoint bytes of storage.

Now, check out this code:

#include <stdio.h>  void c();  void b(const char *a) {     static const char *p = 0;      if (!p) {         p = a;         c();     } else {         if (a==p) {             printf("problem!\n");         }     } }  void c() {     const char a[] = { 0xd, 0xe, 0xa, 0xd, 0xb, 0xe, 0xe, 0xf };      b(a); }  int main() {     c(); } 

Here, c is called recursively once, so according to the rule, the array a should have different addresses in each recursion level. b stores a at the first invocation, and at the second invocation, it checks whether it is the same or not. With a conforming compiler, it should not print "problem!". But actually, with an old compiler (GCC 4.1, clang 6.0), it prints "problem!", so these compilers violate the standard.

A compiler is allowed to make a static only in the case that it can be proven that this change is not observable:

Under the “as-if” rule an implementation is allowed to store two objects at the same machine address or not store an object at all if the program cannot observe the difference

like image 53
geza Avatar answered Oct 16 '22 11:10

geza


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.

like image 39
dascandy Avatar answered Oct 16 '22 11:10

dascandy