I saw following piece of code in a legacy project.
/* token.c */
struct token id_tokens[MAX_TOKENS];
/* analyse.c (v1) */
extern struct token *id_tokens; /*
lets understand same stuff by program
test.c
#include<stdio.h>
#include"head.h"
struct token id_tokens[10];
int main()
{
printf("In original file: %p",id_tokens);
testing();
}
head.h
struct token {
int temp;
};
test1.c with v1
#include<stdio.h>
#include"head.h"
extern struct token* id_tokens;
void testing () {
printf("In other file %p",id_tokens);
}
Output : In original file: 0x601040In other file (nil)
test1.c with v2
#include<stdio.h>
#include"head.h"
extern struct token id_tokens[];
void testing () {
printf("In other file %p",id_tokens);
}
Output : In original file: 0x601040In other file 0x601040
This clearly shows that v1 is not correct and v2 is correct.
/* token.c */
struct token id_tokens[MAX_TOKENS];
/*
id_tokens
+-----+-----+-----+-----+...+-----+
| | | | | | |
+-----+-----+-----+-----+...+-----+
[0] [1] [2] [3] ... [MAX_TOKEN-1]
To access id_tokens[i], add offset of ith element
i.e. i * sizeof(struct token) to the **address**
of array token
*/
So in your analyse.c
, following instructions would be generated with this declaration.
extern struct token id_tokens[];
id_tokens[i]
a. Address of id_tokens that might be linked from other compilation unit is taken
b. offset of i is added
c. Value is referenced
/* analyse.c (v1) */
extern struct token *id_tokens;
/*
id_tokens
+------+ +-----+...
| addr |---------->| |
+------+ +-----+...
To access id_tokens[i], fetch **contetnts** of pointer
token, add offset of ith element i.e. i * sizeof(struct token)
is added to this.
*/
So in your analyse.c
, following instructions would be generated with this declaration:
extern struct token *id_tokens;
id_tokens[i]
a. Contents from address of id_tokens that is linked from other compilation unit is taken.
(Will result in compilation error if present in same compilation unit because of type mismatch)
b. offset of i is added
c. Value is referenced
Let's assume sizeof id_token[0]
is 2
byte and sizeof pointer to id_token[0]
is 4
byte.
Your later declaration may (mis)interprete the id_tokens[0]
& id_tokens[1]
as an address and add some offset to it (which may be an existing or non-existing address, aligned or non-aligned address who knows).
If it is your good day, program may crash or segfault immediately and you get a chance to fix the bug. If it is your bad day, program may just mess up with some other memory or communicate a wrong state to some module which can result in difficult to track bug and cause a nightmare.
Now I guess you understand why you got (nil)
as output in Mr. 32's answer.
The first version is wrong. Arrays are NOT pointers, the declaration extern struct token *id_tokens;
doesn't match the definition type struct token id_tokens[MAX_TOKENS];
.
Reference: C FAQ: I had the definition char a[6] in one source file, and in another I declared extern char *a. Why didn't it work?. Also, see this.