title: Different linkage for extern "C" vs. extern "C" { } in C++
body: <p>I realize that, at first sight, my question <em>might seem</em> an obvious duplicate of one of the many questions here related with the <code>extern</code> keyword, but I was unable to find <strong>any answer</strong> talking about the difference between extern "C" and extern "C" { }. On the contrary, I've found several people stating that the two constructs are equivalent, as I believe it is reasonable to expect. Unfortunately, empirical evidence shows that they really <strong>are not</strong> equivalent. </p>
  
  <p>Here is an example:</p>
  
  <pre><code>extern "C" { const int my_var1 = 21; }
  extern "C" const int my_var2 = 42;
  const int my_var3 = 121;
  
  int main() { }
  </code></pre>
  
  <p>After compiling it with gcc 7, with <code>g++ externC.cpp</code>, I see a remarkable difference:</p>
  
  <pre><code>$ readelf -s ./a.out | grep my_var
      34: 0000000000000694     4 OBJECT  LOCAL  DEFAULT   15 _ZL7my_var1
      35: 000000000000069c     4 OBJECT  LOCAL  DEFAULT   15 _ZL7my_var3
      59: 0000000000000698     4 OBJECT  GLOBAL DEFAULT   15 my_var2
  </code></pre>
  
  <p><code>my_var1</code> and <code>my_var3</code> both have <em>local</em> binding and a C++ mangled name, while <code>my_var2</code> has <em>global</em> binding and actual C linkage. So, it looks like the <code>extern "C" { }</code> has been completely ignored, while the similar <code>extern "C"</code> <strong>without</strong> <code>{}</code> did have effect. That is <strong>super weird</strong> to me. </p>
  
  <p>Things get even more interesting if I remove the <code>const</code> and just try to read the variables:</p>
  
  <pre><code>#include &lt;cstdio&gt;
  
  extern "C" { int my_var1; }
  extern "C" int my_var2;
  int my_var3;
  
  int main() {
      printf("%d, %d, %d\n", my_var1, my_var2, my_var3);
  }
  </code></pre>
  
  <p>When I try to compile this 2nd program, the linker complains that it has been unable to find a reference for <code>my_var2</code>:</p>
  
  <pre><code>/tmp/ccfs9cis.o: In function `main':
  externC.cpp:(.text+0xc): undefined reference to `my_var2'
  collect2: error: ld returned 1 exit status
  </code></pre>
  
  <p>And that means that <strong>in this case</strong> two things happened:</p>
  
  <ol>
  <li><p><code>extern "C" { int my_var1; }</code> <strong>instantiated</strong> in the translation
    unit a variable called <code>my_var1</code> with C linkage.</p></li>
  <li><p><code>extern "C" int my_var2;</code> <strong>declared</strong> an <strong>extern variable</strong>, where
    with <code>extern</code> I mean in the traditional sense
    (like <code>extern int x;</code>), but with "C" linkage. </p></li>
  </ol>
  
  <p>Which, from, my point of view, is inconsistent with the behavior in the 1st case above, using <code>const</code>. In other words:</p>
  
  <ul>
  <li><p>In the 1st program with const</p>
  
  <ul>
  <li><p><code>extern "C"</code> behaved like I expected <code>extern "C" {}</code> to behave
  [change the linkage]</p></li>
  <li><p><code>extern "C" {}</code> instead, did <strong>nothing</strong></p></li>
  </ul></li>
  <li><p>In the 2nd program, without const:</p>
  
  <ul>
  <li><p><code>extern "C" {}</code> behaved like I originally expected [change the linkage] BUT</p></li>
  <li><p><code>extern "C"</code> behaved like:
  <code>extern "C" { extern int my_var2; }</code>
  which is the way to declare an <em>extern</em> variable with C
  linkage (and unfortunately in C++ the keyword <code>extern</code> has
  been reused).</p></li>
  </ul></li>
  </ul>
  
  <p>In conclusion, my question is: can anyone (maybe a compiler expert?) explain the theory behind the reason for <code>extern "C"</code> and <code>extern "C" {}</code> to behave so differently and in such a inconsistent (at least for me) way ? In mine experience with C++, I realized that once you understand in deep details a given concept, even its tricky and complex corner cases start to look pretty reasonable and consistent. Just, you need to see the whole picture very clearly. I believe that is such a case.</p>
  
  <p>Thanks a lot to everybody, in advance.</p>
  
  <hr>
  
  <p><code>Edit[1]</code></p>
  
  <p>[At the end it turned that a similar question <em>did</em> exist here, just I was unable to find it. Sorry for that.]</p>
  
  <p>Thanks to the answers so far, I understand now the subtle difference between <code>extern "C" {}</code> and <code>extern "C"</code>, even if I'd still be curious to understand how we (the C++ developers/ISO committee) ended up with such a solution. It's kind-of like making <code>if (x) foo();</code> to be behave slightly differently than <code>if (x) { foo(); }</code>. Anyway, given this new knowledge, I'd have a few (hopefully) interesting observations to make:</p>
  
  <p>Given that the transformation:
  <code>extern "C" X</code> => <code>extern "C" { extern X }</code> is always correct</p>
  
  <p>It follows that:</p>
  
  <ul>
  <li><p>The only way to define (instantiate) a <code>const</code> variable with C linkage 
  in the current translation unit is to make it <code>extern</code>, even if we want don't want that: the compiler will decide if we're instantiating or just declaring an extern depending on if we initialized the variable with a value: in that case, we're defining, otherwise we're just declaring.</p></li>
  <li><p>The same logic (extern + const) applies to regular <code>const</code> variables with C++ linkage as well. A <code>const</code> variable with C linkage is no different except for the lack of name mangling.</p></li>
  <li><p>From the statements above it follows that, since <code>const</code> implies <em>internal</em> linkage in C++ (but not in C!), the <code>extern</code> when used for a <code>const</code> does not mean <code>extern</code>, but just <em>less internal</em> or <em>more extern than static</em>.</p></li>
  </ul>
  
  <p>In other words:</p>
  
  <ul>
  <li><code>const int var = 23;</code> creates a global variable with internal linkage, like <code>static int var = 23;</code> would except for being placed in a read-only segment.</li>
  <li><code>extern const int var = 23;</code> creates a global variable with regular (external) linkage. The <code>extern</code> neutralizes the implicit <code>static</code>. The result is the same as <code>int var = 23</code> except that with <code>const</code> it will be placed in a read-only segment.</li>
  <li><code>extern const int var;</code> declares a proper extern variable in a foreign read-only segment.</li>
  </ul>