-1

Hello I'm viewing an example of external linkage of function and variable in C.

This is an example that produces random variables.

  1. random.c
#define SEED 20
#define MULT 3124
#define INC 2345
#define MOD 5436

unsigned int call_count = 0; 

static unsigned seed = SEED;  

unsigned random_i(void) {

    seed = (MULT * seed + INC) % MOD;

    call_count++;

    return seed;

}

double random_f(void) {

    seed = (MULT * seed + INC) % MOD;
    call_count++;

    return seed / (double)MOD;
}
  1. and this is main.c
#include <stdio.h>
#include <stdlib.h> 

#pragma warning (disable:4996)

unsigned random_i(void); // I wonder why this prototype has no "extern" specifier
double random_f(void); // I wonder why this prototype has no "extern" specifier

extern unsigned call_count;

int main(void) {

    register int i;

    for (i = 0; i < 10; i++)
        printf("%d ", random_i());

    printf("\n");

    for (i = 0; i < 10; i++)
        printf("%lf ", random_f());

    printf("\nCall count : %d\n", call_count);
    
    return 0;
}

in this short program, I wonder why those of two function prototype has no "extern" specifier AND why this code is compiled without an error.

Because what I know is that when I use variables or functions that is in other source code, I have to do it with extern specifier for example extern int a=10;.

Please let me know.

Thanks.

Clifford
  • 88,407
  • 13
  • 85
  • 165
ssrr00
  • 13
  • 3

3 Answers3

2

Both functions and data definitions outside of a function block have implicit external linkage. However when it cones to a declaration, the extern keyword is required for data object otherwise it is a definition. For functions a prototype is unambiguously not a definition because it has no body.

Regarding:

I have to do it with extern specifier for example extern int a=10;

Not quite, in this case extern int a=10; is a definition not a declaration because you have included an initialiser. It is the same as int a=10; and would result in a duplicate definition error if also defined elsewhere.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • Even more: *all* function identifiers default to external linkage when no linkage is explicitly declared, including those declared inside function bodies. – John Bollinger Jan 31 '21 at 15:03
  • Now I see that global functions are implicitly external, right?(By C standard). – ssrr00 Feb 01 '21 at 08:47
1

Symbols at global scope are externally visible by default. This applies to both variables and functions. The extern keyword is only needed to prevent multiple definitions of a symbol. It states that the current declaration is defined elsewhere.

extern is required for call_count since it would otherwise be a definition. It is not required for the declaration of global functions since there is no definition.

Note that

extern int a=10;

generates a warning in gcc:

warning: ‘a’ initialized and declared ‘extern’ 
stark
  • 12,615
  • 3
  • 33
  • 50
  • Help me out here with "It is not required for the declaration of global functions since there is no definition." You seem to be trying to draw a parallel between variables and functions, but the actual usage is not analogous. You observe correctly that the declaration of `call_count` in main.c must include `extern` to avoid that translation unit defining that object, but main.c does not define the `random_i()` and `random_f()` functions either, even though it does not explicitly declare them `extern`. This difference seems to be near the heart of what the OP is asking about. – John Bollinger Jan 31 '21 at 15:11
  • @JohnBollinger Added some clarification. – stark Jan 31 '21 at 15:22
  • Your clarification improves this answer, but it does not speak to the point I raised. There is an essential difference between the implications of explicit `extern` on object declarations and the implications of explicit `extern` on function declarations. With or without `extern`, the OP's main.c does not contain an explicit definition of `call_count` any more than it contains definitions of the two random functions. – John Bollinger Jan 31 '21 at 15:48
  • @JohnBollinger `unsigned call_count;` at file scope may be a tentative definition, but it is still a definition. – stark Jan 31 '21 at 15:56
  • Not according to the specification, @stark. As the terms are used in the language specification, "tentative definitions" are not "definitions". They cannot be, because only one definition of each identifier is allowed, but there may be any number of tentative definitions, even in the same translation unit. When a TU contains a tentative object definition but not explicit definition, then the semantics are as if it also contained a definition of that object (that is, there is a separate, implicit definition). See paragraph 6.9.2/2 of C11 or C17. – John Bollinger Jan 31 '21 at 16:07
  • But you are focusing on the wrong point. My objection is about what you say about functions -- which is, after all, the main topic of the question -- not what you say about objects (even though the latter is a bit imprecise). – John Bollinger Jan 31 '21 at 16:08
0

All functions are extern by default so prototypes do not need extern. But you can, of course, use it if you wish.

unsigned random_i(void); === extern unsigned random_i(void);

0___________
  • 60,014
  • 4
  • 34
  • 74
  • Perhaps you meant "by default"? Functions declared `static` are not `extern` -- these are mutually exclusive. – John Bollinger Jan 31 '21 at 15:03
  • @JohnBollinger if you specify linkage specifier explicitly it will change the default function linkage. – 0___________ Jan 31 '21 at 15:26
  • Yes, that's my point. It is inconsistent with your "All functions are extern by definition", which leaves no room for functions to be other than extern. Since you seem to understand the actual semantics, I suppose I guessed correctly that you simply chose poor wording. – John Bollinger Jan 31 '21 at 15:51