1

The question is not "why can't I initialize a variable declared as extern", because it's something completely possible with file scope variables (not with block scope variables). The thing is that GCC yields a warning (with -Wall switch) in this particular case:

extern int n = 10;  // file scope declaration

GCC yields:

test.c:5:12: warning: ‘n’ initialized and declared ‘extern’

The code works perfectly, though.

Furthermore, note that the following definition is absolutely equivalent to the first one:

int n = 10;  // file scope declaration

In both cases, the variable has the same linkage and storage type. The thing is that, being both absolutely equivalent, the second version doesn't yield any warning in GCC (with -Wall).

Why is that?

My guess is that you usually use extern to explicitly set a reminder about the fact that this is a declaration that refers to an external object defined elsewhere, so that you shouldn't (though you could) initialize the variable (bear in mind that the standard doesn't let you define a variable twice inside the same linkage, in this case, external).

So, is that a right guess, or perhaps there's more to it, which I'm not able to see?

Pep
  • 625
  • 4
  • 19
  • It's a quirk of GCC — it is not the way that C is normally written and the compiler generates a warning. It is simplest to avoid using the `extern` when initializing the variable. You get that warning from GCC for older versions of the C standard; it is not tied to C18. – Jonathan Leffler Aug 27 '20 at 12:38
  • 4
    I think this boils down to a "why?". What would be a situation where it's useful to do this? See [this post](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45977#c0) from 2010 on the GCC Bugzilla. The [first comment](https://gcc.gnu.org/bugzilla/show_bug.cgi?id=45977#c1) on it notes that this is about coding style, and describes this pattern as "extremely unidiomatic". – Thomas Jager Aug 27 '20 at 12:42
  • Some of the C rules about `extern` are a mess because the language evolved with different practices over time, resulting in kludges to allow certain things, disallow others, and give certain meanings. The compiler warnings are a consequence of this muddled history. It is common practice to use `extern` in non-definition declarations and not in definitions, and so the compiler warnings about its use in definitions, but the C standard allows it. – Eric Postpischil Aug 27 '20 at 13:27
  • Related to this question: https://stackoverflow.com/questions/57957168/how-do-i-disable-a-gcc-warning-which-has-no-command-line-switch – th33lf Aug 27 '20 at 13:27
  • @th33lf well, that question is more related to disable warnings that, like the one under discussion, don't have a specific switch. – Pep Aug 27 '20 at 13:31
  • @PepeDeTicher The warning he wants to disable is the same warning you have! Also [this one](https://stackoverflow.com/questions/4268589/warning-in-extern-declaration/21585233#21585233) – th33lf Aug 27 '20 at 13:32
  • @th33lf yes, that's true. – Pep Aug 27 '20 at 13:34

2 Answers2

2

A compiler can warn about anything it likes to. If it is attentive, it warns about things it considers as "suspicious".

So it does here.

My personal opinion about the reasoning agrees to yours:

My guess is that you usually use extern to explicitly set a reminder about the fact that this is a declaration that refers to an external object defined elsewhere so that you shouldn't (though you could) initialize the variable (bear in mind that the standard doesn't let you define a variable twice inside the same linkage, in this case, external).

That GCC finds it suspicious to initialize an explicit extern declared variable because it is usually more common to define the variable in one file and then in another file, which can depend on the context, cause an error at linking and indeed can be the reason but our assumptions aren't worth much.

The question for the actual "why" you need to ask the implementors of GCC itself.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • To be fair, the `extern` there is clearly redundant and adds nothing to the statement. It does no harm, but can also be safely omitted. The compiler is also trying to prevent a potential linker error, in case the actual definition of the variable is present in another translation unit. – th33lf Aug 27 '20 at 13:41
0

The keyword extern is used to declare a variable but not define it (similar to function declarations). It is typically used in header files to export a variable from a module. However, it is often better to introduce a function which returns its value.

Example:

M.h

extern int M_n;

M.c

int M_n = 10;
August Karlstrom
  • 10,773
  • 7
  • 38
  • 60
  • 1
    While what you say is the typical use, there's nothing invalid about the code being shown in the question. It's just an unusual, unintuitive use for `extern`. I mostly have an issue with the first sentence. – Thomas Jager Aug 27 '20 at 12:59
  • @ThomasJager Even if it's valid, why would you do it? Declarations using *extern* should be in header files and variable definitions should be in implementation files. – August Karlstrom Aug 27 '20 at 13:09
  • 1
    There is a recommended rule that, generally, non-definition declarations of names to be used in multiple translation units should be in headers and definitions should be in source files. That rule is recommended **because** headers are used to make names known to other translation units (so they should have declarations) and defining objects or functions in them would result in multiple definitions. You say declarations using `extern` should be in header files. Why is there such a rule? What is the “**because**” that causes such a rule and says `extern` should not be used in source files? – Eric Postpischil Aug 27 '20 at 13:25
  • @AugustKarlstrom I agree, and that's the point I make in my comment on the question. However, I don't feel that you answer actually addresses the question at all, only answering "What is `extern`?". The first sentence implies that the variable with `extern` is not given any storage if no storage is created for it in another unit. – Thomas Jager Aug 27 '20 at 13:29
  • @EricPostpischil Because, as far as I can see, there is no use case for *extern* in implementation files. If there is, please let me know. – August Karlstrom Aug 27 '20 at 13:30