23
#include<stdio.h>
#include<stdlib.h>
#define GREY 1
#define BLACK 0
#define WHITE 2
typedef struct node * graph;
typedef struct stack * snode;

graph cnode(int data);          //cnode is to create a node for graph
void cgraph(void);
struct node {
        int data, color;
        struct node *LEFT, *RIGHT, *TOP, *DOWN;
};//this structure defines a node of the graph

struct stack {
struct stack *priv;
struct cgraph *graph_node;
};// this is to define a structure which should hold node of a structure

    extern snode sroot;

I defined a header file (declaration.h) as above and following is a c program(stack.c) I am making which would be used in the library I am developing

#include<declarations.h>
void cstack (graph temp);
void stackpush(snode stemp);
extern int stack_counter = 0;

sroot=NULL;
void cstack (graph gtemp) //cstack is to create stack
{
   snode spriv,some;
  if (stack_counter==0)
  {
   sroot=stackpush(gtemp);
    spriv=sroot;
   stack_counter++;
   }
   else{
   some=cstacknode(gtemp);
    some->priv=spriv;
    spriv=some;
  }

}

//struct stack is representing a stack
//struct node is representing a node in graph

snode  cstacknode (graph gtemp)
//this function should create a node of the stack which should be storing the graph node as a pointer
{
 snode an;
 an=(snode)malloc(sizeof(snode));
 an->graph_node=gtemp;
 an->priv=NULL;
 return an;
}

void stackpush(snode stemp)
{

}

both the above files are in same directory. I compiled the above file stack.c cc -I ./ stack.c I following warnings

stack.c:4: warning: ‘stack_counter’ initialized and declared ‘extern’
stack.c:6: warning: data definition has no type or storage class
stack.c:6: error: conflicting types for ‘sroot’
./declarations.h:21: note: previous declaration of ‘sroot’ was here
stack.c:6: warning: initialization makes integer from pointer without a cast
stack.c: In function ‘cstack’:
stack.c:12: warning: passing argument 1 of ‘stackpush’ from incompatible pointer type
stack.c:3: note: expected ‘snode’ but argument is of type ‘graph’
stack.c:12: error: void value not ignored as it ought to be
stack.c:13: warning: assignment makes pointer from integer without a cast
stack.c:17: warning: assignment makes pointer from integer without a cast
stack.c: At top level:
stack.c:27: error: conflicting types for ‘cstacknode’
stack.c:17: note: previous implicit declaration of ‘cstacknode’ was here
stack.c: In function ‘cstacknode’:
stack.c:32: warning: assignment from incompatible pointer type

I want to know when I declared a variable as extern which I have marked bold why do I get that as a warning any thoughts on that and if some one wants to share any other thing on remaining errors then let me know.

reality displays
  • 731
  • 3
  • 9
  • 18
  • See also the much more recent question [How to define `extern` variable along with declaration?](http://stackoverflow.com/questions/24436770/how-to-define-extern-variable-along-with-declaration) – Jonathan Leffler Jun 26 '14 at 18:49
  • I believe nmichaels's answer (second up as of writing this) is the correct answer: Declare your extern in a header file and define it without extern in your c file. If other files wants to use this variable they will have to include the header and link with the c file. This way you also have a single place to declare the type and the compiler can check for mismatch (I'm not sure the linker would notice if two files declared the same extern differently). – Thomas Guyot-Sionnest Mar 17 '22 at 17:46

4 Answers4

53

While your code contains a number of rather serious and obvious errors (already covered in other answers), the warning you put into the title of your question is a completely superfluous meaningless warning. GCC compiler is notorious for issuing useless warnings. Many of those warnings seem to be derived from someone's incompetent and completely unsubstantiated belief that doing something is somehow "wrong", while in reality there's nothing wrong with it.

In your case the warning is triggered by

extern int stack_counter = 0;

declaration. Apparently, the "author" of the warning believed that extern specifier should be reserved for non-defining declarations. In this case the presence of initializer = 0 turns the declaration into a definition (and thus formally makes that extern optional). Nevertheless, there's no error in it and, in fact, extern might be quite welcome here to emphasize the fact that stack_counter is intended to be a global variable.

Again, whether you need a global variable here or not is a different question and, again, your code contains a massive number of other errors. But the warning you seem to focus your attention on is not really worth it. Just disable this warning in compiler settings (and, please, write a rude letter about it to GCC team).

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • 19
    To be fair, this is a warning that can foreshadow (and help solve) a linker error (multiple definition). For example... in TU 1 one creates a global and assigns it, then in TU 2 we copy the declaration and then prepend `extern` to that declaration. The initialization being present with extern makes the extern mean something different and thus causes two instances of this variable to be created and the linker barfs... This is not to say that your point is any less valid, but this is probably the reason for the warning to exist... – Steven Lu Jul 17 '14 at 20:27
  • 6
    @StevenLu: So, GCC warns before the error happens, and then the error happens at the link phase anyway. Great stuff. – alecov Mar 25 '16 at 16:53
  • 5
    Well, code like if (x=1) { ...} is perfectly legal, and yet a warning there is usually welcome. – fwyzard Oct 18 '17 at 09:07
  • 2
    @alecov That's why you should really always use `-Werror`. GCC is amazing at making your invalid code compile, but it's better to prevent incorrect code from compiling at all. – yyny Aug 22 '18 at 14:34
  • 1
    @YoYoYonnY: `-Werror` is an overkill. It will prevent correct code from compiling. GCC has `-pedantic-errors`. It is not perfect, but it makes more sense than than `-Werror`. – AnT stands with Russia Aug 22 '18 at 14:40
  • @AnT the only warnings produced by `-std=c11 -pedantic -Wall -Wextra` that I would consider 'correct code' are unused symbol warnings (mostly unused parameters), and you can disable them with `-Wno-unused` / `-Wno-unused-parameters` for debug builds. I frequently disable `-Werror` altogether when I'm prototyping a new feature. But I would still turn them on for release builds. Code that compiles with one compiler on one system might not run elsewhere. – yyny Aug 22 '18 at 17:23
  • 3
    The intended use is to have a single external *definition* in one file, e.g. `int a;` and one or more *declarations* `extern int a;` in other files. The use of `extern` can then signal that the variable is *defined* in some other location (possibly in the same file, but most likely in a different source file). `extern int a = 5` violates this idiom. – Andrey Portnoy Apr 08 '19 at 06:34
  • 2
    @AndreyPortnoy No, that is not the intended use. The intended use of `extern` specifier is to give an identifier *external linkage*. In this role it can be used uniformly in declarations and in definitions. In the former contexts it "imports" the name, in the latter contexts it "exports" the name. It is perfectly symmetrical. The latter usage is redundant in C (as opposed to C++), but still it is correct. – AnT stands with Russia Apr 08 '19 at 06:39
  • 1
    @AnT It *can* be used in definitions as per standard. The idiomatic use, however, is to not put `extern` in definitions (see K&R, p.80-81). I agree though that the GCC warning can be irritating because it does not explain itself. – Andrey Portnoy Apr 08 '19 at 06:46
  • 2
    Fun fact: `clang` also has this warning: https://clang.llvm.org/docs/DiagnosticsReference.html#wextern-initializer – Andrey Portnoy Apr 08 '19 at 06:54
  • Thanks for the explanation. I was not confident firstly since I am not familiar with the legal tone of the standard. – user26742873 Aug 31 '21 at 18:40
  • I don't buy this... If you have an actual use case for defining the extern in C file let us know, but afaik the OP's warning can be fixed simply by declaring the extern in his header and removing extern from the C file (if the header is included the extern declaration will still be used. – Thomas Guyot-Sionnest Mar 17 '22 at 17:50
  • @Thomas Guyot-Sionnest: In C there never any real need to use `extern` in a variable/function*definition* (aside from the special case of `extern inline` with functions), since external linkage it is always implied by default (there's even no need to make sure the header is included). This nevertheless does not cancel the fact that the feature is present in the language. So, I don't understand what exactly you "don't buy". – AnT stands with Russia Mar 25 '22 at 16:28
  • @Ant so you suggest I can access variables defined in other linked objects without even using `extern`? I haven't tested but it sound the same to me: the answer says that the gcc warning is useless, IMHO it's not. If you don't need the extern on definition then don't use it, and maybe only on declaration (and even if it's not "needed" it makes it explicit, I'm guessing it will at least prevent you from re-defining it on your own source...). I'm just an amateur C coder, but sounds to me we can both DTRT and have gcc not complain needleesly. – Thomas Guyot-Sionnest Mar 27 '22 at 13:35
  • 1
    @Thomas Guyot-Sionnest: No, I'm saying that `extern` is useful in *non-defining declarations* and is redundant in *definitions*. In order to access defined in other translation unit you use a *non-defining declaration* with an `extern`, which is a tangible use of `extern`. – AnT stands with Russia Mar 28 '22 at 17:23
8

The extern declaration in your header file lets modules other than the one in which the variable is defined use it. If it's supposed to be defined as int stack_counter = 0 and live in stack.c, define it like that and put an extern stack_counter in the header.

On line 6 of stack.c, you didn't define a storage class for sroot. Since it's externed in the header, I assume you meant to type snode sroot=NULL.

Fix those, then implement stackpush (make sure it doesn't return void) and deal with the rest of your warnings in order. Note that in C, you have to either use forward declarations of functions (with prototypes) or define your functions before they're used. The cstack function should probably be the last function in the file.

nmichaels
  • 49,466
  • 12
  • 107
  • 135
  • Oh ok thanks for pointing out these errors I have modified my file declarations.h my both the programs I want to post them here but I am not able to see any code tag by which I can post the modified thing let me know I want to discuss this further as how do I put the c programs in my reply so that code is readable on stackoverflow. I tried adding backtick ` and also ' but none worked. – reality displays Nov 24 '10 at 16:35
  • 1
    @Bond: Can't be done in comments. Your best bet is to update the question to reflect the changes. Or, if you made changes that got you stuck elsewhere, ask a new question. – nmichaels Nov 24 '10 at 16:46
5

I just had this warning with gcc and it's a simple fix. stack_counter should not be initialised in the header, but rather in a source file that includes it. So the header should just use:

extern int stack_counter;

Then declare and initialise stack_counter in global scope of just one source file that includes that header:

int stack_counter = 0;
David Yeager
  • 596
  • 5
  • 9
0

Clang still issues a warning for this. The line

extern int counter = 0;

will trigger the warning:

warning: 'extern' variable has an initializer [-Wextern-initializer]

This warning is not important, as defining the variable with

int counter = 0;

still yields a static duration and external linkage by default. Indeed, if no storage-class specifier is provided, the defaults are:

  • extern for all functions
  • extern for objects at file scope
  • auto for objects at block scope

There is also something called a tentative definition which is an external declaration without an initializer, and either without a storage-class specifier or with the specifier static.

A tentative definition is a declaration that may or may not act as a definition. If an actual external definition is found earlier or later in the same translation unit, then the tentative definition just acts as a declaration.

So the following line

int counter;

is a tentative definition that declares and defines counter with the implicit initializer = 0 (or, for array, structure, and union types, = {0}).

explogx
  • 1,159
  • 13
  • 28