Some mystic with 'extern' pointer to struct in C

277 views Asked by At

I have the following pieces of code with 3 global pointers to structs:

structs.h:

#pragma once

typedef struct Bignum {
  int digit;
  struct Bignum *next;
  struct Bignum *prev;
} Bignum;

typedef struct Stack {
  struct Bignum *head;
  struct Bignum *tail;
  char sign;
  struct Stack *next;
} Stack;

Bignum *num_tail;
Bignum *num_head;
Stack *stack_head;

globals.c:

#include "structs.h"

Bignum *num_tail;
Bignum *num_head;
Stack *stack_head;

When I compile these with other .c files (where I include structs.h and work with num_tail, num_head and stack_head), compilers (both clang version 3.8.0 and gcc 5.4.0) compile this code without errors and program works as it should. But, as far as I'm concerned, this code should not be normally compiled and work because of lack of extern modifier in structs.h. Why does it work? :)

UPD: Yes, the answer is tentative definitions. Really, after initializing pointers to NULL, compilers give an error message. Thanks for all the replies!

2

There are 2 answers

0
Petr Skocik On BEST ANSWER

Tentative definitions. You don't assign a value to those globals so they're treated as tentative definitions. The right-hand side ={0}; is assumed but only tentatively. If there's no real definition, the tentative definitions will get merged. If there is one, it'll win over the tentative ones without creating a linker conflict. This is normally implemented via common symbols (marked C in nm output), which means you can have tentative definitions for the same symbol even in multiple translation units. (I think it's best to not rely on this feature and stick to extern declarations coupled with nontentative definitions.)

0
artm On

By the default there is no need for extern because non-static variables already have external scope.

In fact the declarations in globals.c are redundant.

Bignum *num_tail;
Bignum *num_head;
Stack *stack_head;

The compiler would give errors only for the case of redefinition, for example if num_tail in header and source are both initialised.