C header file and extern

In the header file data.h i got:

const char ack_msg[] = "ack: received your msg\n";

In the code file server.c i got:

extern const char ack_msg[];

And else it is only used in a function call:

user$ grep ack_msg *c *h
server.c:extern const char ack_msg[]; 
server.c:    n = write(clientsfd, ack_msg, strlen(ack_msg)); 
data.h:const char ack_msg[] = "ack: received your msg\n"; 
user$ 

But i get this error when compiling:

user$ ls
checkr.c  checkr.h  client  client.c  data.h  server.c
user$ gcc checkr.c server.c -Wall -Wextra --pedantic -o server
/tmp/ccdKHyIr.o:(.rodata+0x0): multiple definition of `ack_msg'
/tmp/ccUnDvRc.o:(.rodata+0x0): first defined here
collect2: ld returned 1 exit status
user$ 

I got data.h included in server.c:

user$ grep data.h server.c 
#include "data.h"
user$ 

data.h:

#ifndef DATA_H
#define DATA_H
const char *progname;
#define BUF_SIZE 512
const char ack_msg[] = "ack: received your msg\n";
#endif

Thanks.

You got it exactly backwards.

You should put this in the header file:

extern const char ack_msg[];

...and this in one and only one C file, call it "data.c" perhaps:

#include "data.h"

const char ack_msg[] = "ack: received your msg\n";

The string can be used in any C file which does #include "data.h"

1 Like

Thanks so much, it seems clear now. I got another question about header files. Say i got checkr.h with:

void check_argc(int, int); 

and the function in checkr.c:

 void check_argc(int argcount, int n) {         if ( argcount != n ) {                 fprintf(stderr, "ERROR: wrong argument count\n");                 usage();                 exit(EXIT_FAILURE);         } } 

From what you say i think i would need to use "extern" in checkr.h ? Can i also use it in the main file (called server.c) ? I know that i don't have to, but it helps me a bit to keep track of the functions without opening and closing files all the time (or using :vsplit). I think it has to do with definition and declaration? I read about it quite often, but never really understand it and usually forget it soon.

Here is how extern works.

You have three C files. File1 declares the variable foo (we are just doing variables, functions work the same).

int foo;

File2 and File3 both use the variable. It "lives" in File1. So it is "extern"[al] to the scope of those two C files.

To reference foo and have the linker do its magic, each of File2 and File3 has to have an

extern int foo;

Somewhere. That somewhere can be directly in the code of both files: file2 and file3. It can also be in a header file that is common to both files.

Using

#define

operations you can make all 3 files: file1 file2 and file3 see it correctly. Just using myheader.h

myheader.h:

#ifndef MAINFILE
int foo;
#else
extern int foo;
#endif

File1.c:

// prevent File1.c from "seeing" the extern version of foo by defieing MAINFILE
#define MAINFILE
#include "myheader.h"

File2.c:
File3.c:

#include "myheader.h"

This is an example, not best practice necessarily.

1 Like

Thanks. Your explanation and example makes it more clear (also thanks for pointing out it may not be best praxis, but for now i just try to understand the general idea).

I think you say that: header files are (or can be ) used _instead of declaring the variable foo as extern in File2 and File3. foo is defined in File1 (and storage is set aside for it). File1 includes myheader.h too, and if foo is declared (File2 and File3) or defined (File1) is decided by the #ifndef Mainfile and #define Mainfile in File1.

I read in �The C Programming langauge"; (As "C A modern approach" was not clear on the subject) and in chapter 1 "External variables and scope" (page 33 for me) it says the following (or that is what i understand):

  • a definition creates a variable and sets aside storage
  • a declaration only announces the nature of a variable
  • extern says that the definition is elsewhere and only declares
  • header files include declarations, not definitions
    Is both correct (What i understood of your post and what i understood of the book)?

I think i am getting closer to understand it. Let me rethink and read again.Really thanks.

If you don't define a function's contents with { } right then and there, it'll be assumed to be extern. This is very unlike variables, which never assume they're external unless you say so.

extern used to be a bigger deal for functions when there were many methods of linking -- there could be several kinds of extern functions, and you'd use extern to tell the compiler which they are with extern dllexport functionname(); or what have you. Sometimes this is still important when mixing C with other languages, to guarantee your function calls are generated in a way foreign code can understand.

1 Like