0

Thoroughly confused. I'm frustrated because I think it's important to know precisely how scope and linkage work, but I've been seeing conflicting info about extern and my compiler/linker is contradicting what I've read.

----------main.c--------------

int int1;

void main()
{  int1=6;
   printf("\nMain - int1 = %4d", int1);
   blippy();
   printf("\nMain - int1 = %4d", int1);
   return;
}

-------------second.c-------------

int int1;

void blippy()
{ printf("\nSecond - int1 = %4d", int1);
  int1++;
  return ;
}

Output is:

Main - int1 =    6
Second - int1 =    6
Main - int1 =    7

as if both instances of int1 pointed to one variable with external linkage. I would have expected the compiler to either throw a multiple definition error or treat them as static. I'm using Codeblocks, and I don't know if it's doing anything presumptous behind the scenes.

MoDean
  • 1
  • 1
  • These define a "common" symbol. See my answer: https://stackoverflow.com/questions/64626917/global-variables-and-the-data-section/64627070#64627070 – Craig Estey Apr 23 '21 at 18:11
  • @MoDean The compiler can not determine that the variable is defined twice. The linker should issue a message. In fact the behavior is undefined. – Vlad from Moscow Apr 23 '21 at 18:17
  • 1
    Re “I'm using Codeblocks”: Codeblocks is an IDE. That does not tell us which compiler you are using, nor which version. Codeblocks can use multiple compilers. – Eric Postpischil Apr 23 '21 at 18:21
  • @Vlad from Moscow. Yes, the linker. I must learn to be more precise as I have the bad habit of regarding the compiler and linker as one black box.The behaviour being undefined seems sloppy. Can't be many impediments to implementing a 'if it doesn't say extern, it 'aint external rule. – MoDean Apr 23 '21 at 19:36

1 Answers1

4

Largely for historic reasons, int int1; is neither a plain declaration nor a plain definition. It is a tentative definition. If there is no regular definition of int1 in the translation unit (the source file being compiled, including all the files it includes), and there is only one definition of it in the whole program, the tentative definition will act as a regular definition.

However, if you have tentative definitions (without regular definitions) of the same identifier in multiple translation units, the behavior is not defined by the C standard. Some compilers, including GCC until recently, allow multiple tentative definitions and allow the linker to coalesce them into a single definition. Starting with version 10, GCC does not do this and allows the linker to treat them as multiple definitions, unless requested otherwise by a switch, -fcommon.

You can make int int1; into a regular definition by providing an initializer, int int1 = 0;.

Some additional information is here and here.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • @EricPostpischil.Thanks Eric.Safest to always use modifier then. Explains my issue and leaves me unsatisifed with the state of information out there about linkage. Almost every tutorial out there either implicitly or explicitly states that the extern modifier is required to make a name visible across TUs. Seen nothing thus far about tentative definitions. This kind of thing is why I'm irritated by the kick the can down the road approach to teaching languages.If you don't teach linkage in detail early on students are going to waste a lot of time writing code that they don't understand. – MoDean Apr 23 '21 at 19:05
  • @Eric Postpischil - According to the C standard, **6.9.2 External object definitions** §2 and §3, a _tentative definition_ **is** _a declaration_. – Armali Apr 23 '21 at 19:06
  • @EricPostpischil. I added the bit about Codeblocks because the code was created as part of a .cbp project and I didn't know if Codeblocks got clever in the way it manages multi file C projects. I would expect it not to, but you never know. – MoDean Apr 23 '21 at 19:14
  • 1
    @Armali: Yes, all definitions, including tentative definitions, are declarations too. I meant it was not just a declaration. I have updated to indicate that. – Eric Postpischil Apr 23 '21 at 19:19
  • Likely a poisonous inheritance from Fortran. – SergeyA Apr 23 '21 at 19:58