0

I have a simple structure in dbinfo.h viz.

typedef struct {
   int fields;
} dbinfo;

In the main program I have:

#include <string.h>
 ...
#include "dbinfo.h"
extern dbinfo *tst_info;

void main() {

tst_info = (dbinfo *) calloc(1, sizeof(dbinfo));

dbinfo.fields = 3;

printf("\n number of fields = %d"), getnumflds());
...
}

In another file utilities.c I have

#include "dbinfo.h"
extern dbinfo *tst_info;

int getnumflds() {

   return tst_info.fields;
}

When I try to link I get undefined symbols in utilities.c of tst_info. If I remove the extern then I get no unresolved symbols, but the value of fields is 0.

What am i doing wrong here?

I simply want to be able to use and change the value of 'fields' that was set in main in other functions compiled separately.

Been a long time since I used C and having trouble accessing those neurons!

John Wooten
  • 685
  • 1
  • 6
  • 21
  • 2
    Exactly, to tell a bit more. Extern just tells "the variable is elsewere compiler, trust me." But you never actually make it, so the linker does not find it. Just remove the extern from one of the files. – Paolo.Bolzoni Aug 01 '17 at 16:08
  • Don't understand. In the main program, I specify it is extern and alloc it. – John Wooten Aug 01 '17 at 16:11
  • When I remove the extern from the main program, and reference 'fields' in the subroutine it is zero even though I set it to 3 in the main program. – John Wooten Aug 01 '17 at 16:12
  • Don't abuse extern variables. All data needed in a function should be passed to it as arguments. – n. m. could be an AI Aug 01 '17 at 16:15
  • It looks to me like you never actually _define_ the symbol anywhere, meaning that it has no address allocated within your program, and so accessing it becomes pure UB. The particular results you observe are then just happenstance. – underscore_d Aug 01 '17 at 16:20

2 Answers2

2

All definitions of tst_info must be extern except one. The extern keyword on a variable in a certain object file tells the linker to refrain from allocating space for it in the data segment, because storage for the variable will be provided in some other object file. If all object files define the variable as extern, then there is no object file that provides storage for it.

You can read more about this than you can handle in this post: https://stackoverflow.com/a/1433387/773113

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • Detail: "must be extern except one" slightly over-states. `extern int foo; int foo; int foo = 5;` is valid as `int foo;` is a tentative definition. – chux - Reinstate Monica Aug 01 '17 at 16:48
  • @chux true, but I am not sure how I could avoid over-stating and at the same time refrain from suggesting a practice which is non-portable and therefore un-advisable. – Mike Nakis Aug 01 '17 at 17:10
1

You are declaring tst_info as extern in both translation units. The extern keyword means it’s available elsewhere, in some external translation unite. Somewhere, you need to actually define it by not having the extern keyword and instead setting an initial value (which can be the result of calloc, or NULL, or something else).

You might also find it easier to declare a global dbinfo instead of a dbinfo *, depending on the usage of your program. The more data you can move out of dynamic runtime allocation, the better.

Daniel H
  • 7,223
  • 2
  • 26
  • 41