extern declaration, T* v/s T[]
c, declaration, extern, language-lawyer
Solution
/* 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.
Problem
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; /* Raised my eyebrow, id_token declares a pointer */ ``` I insisted on changing `analyse.c` to contain the declaration as below: ``` /* analyse.c (v2) */ extern struct token id_tokens[]; /* I am happy with this. id_tokens declares array of unspecified size. */ ``` I want `v2` because `pointer to T` is not same as `array of T`. My friend's counter argumented that behaviour of both are same, so it doesn't matter whether I use v1 and v2. Question 1: Does array of incomplete type deplete to a pointer? Question 2: Is my friend right that both versions are behaviorally guaranteed to be equivalent?