extern declaration, T* v/s T[]

后端 未结 3 855
一向
一向 2020-12-15 00:56

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; /*         


        
相关标签:
3条回答
  • 2020-12-15 01:33

    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.

    0 讨论(0)
  • 2020-12-15 01:34
    /* 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.

    1. 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:

    1. 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.

    0 讨论(0)
  • 2020-12-15 01:49

    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.

    0 讨论(0)
提交回复
热议问题