This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

'extern' keyword for an array

In file AAA.c

const char CMD_Fire[] = "FIRE";

In file BBB.c

extern const char CMD_Fire[];

It seems that, the compiler is not able to know the size of CMD_Fire[], when compiling BBB.c

So, I have to hard code the size of CMD_Fire[] in BBB.c

Then, if I change the command to "Fire it!", I will need to change the size of CMD_Fire[] everywhere.

Is there any skill to handle this?

  • The sizeof() operator should do the trick.

    Alternatively, you use a #define to explicitly specify the length of the array, altough that may be somewhat bothersome if the length of the string is changed frequently.

  • Of course it isn't - because you have not provided it with that information!

    This has nothing to do with ARM or Keil - this is standard 'C' behaviour!

    A 'C' compiler "sees" only one "compilation unit" at a time. In this case, the only information available in the "compilation unit" is your extern declaration:

    extern const char CMD_Fire[];
    


    which, clearly, contains no length information!

    In this particular case, since it's a string, the best approach would probably be to use string functions - which will automatically detect the end of the string (and, hence, its length) at run-time.

    Alternatively, proceed as follows:

    cmd.h

    #define LEN_CMD_FIRE 5 // Remember to count the NUL!
    
    extern const char CMD_Fire[LEN_CMD_FIRE];
    

    AAA.c

    #include "cmd.h"
    
    const char CMD_Fire[LEN_CMD_FIRE] = "FIRE";
    

    BBB.c

    #include "cmd.h"
    
    // now you can use CMD_Fire and LEN_CMD_FIRE...
    

  • No, it won't - not for an array of unspecified size like this!

    See: c-faq.com/.../extarraysize.html

  • "The sizeof() operator should do the trick."

    What - Used within bbb.c ?

    Not sure that's the case. The compiler won't know the details of the external array when it is compiling bbb.c.

  • cmd.h

    
    #define TXT_CMD_FIRE "FIRE" // The text
    #define LEN_CMD_FIRE 5      // Remember to count the NUL!
    
    extern const char CMD_Fire[LEN_CMD_FIRE];
    

    AAA.c

    #include "cmd.h"
    
    const char CMD_Fire[LEN_CMD_FIRE] = TXT_CMD_FIRE ;
    

    This means that only 1 file - cmd.h - has to be edited to update the string(s)...

  • Thanks for all the replies.

    Many thanks to Andy's helps and the very good examples.

    I know that I still lack a lot of fundamental knowledge; sorry for that.

    If I do this globally:

    extern const char TEST_COMMAND[];
    const char TEST_COMMAND[] = "TEST";
    

    It is OK.

    If I do this locally:

    void CMD_Handle(void)
    {
        extern const char TEST_COMMAND[];
        const char TEST_COMMAND[] = "TEST";    // Line 517
    
        UART3sbWRITE( (BYTE *)TEST_COMMAND, 4 );
        UART3sendKICK();
    }
    

    I get the error.

    source\RS485.c(517): error:  #101: "TEST_COMMAND" has already been declared in the current scope
    

    I think that, I don't really understand "extern". I am confused.

  • The stability of our internet connection is very bad. So my Firefox was just frozen, then some error occured.

  • John,

    It goes wrong because you tell your toolchain that the symbol TEST_COMMAND[] is defined in another C module (by the extern clause) but immediately after that, you make a local definition that collides this the previous, global one.

  • No, it won't - not for an array of unspecified size like this!<p>

    I see .. I rarely use sizeof(), so I'm not aware of all of its limitations.

    Another thing, though - the char array is initialized as a string, so it is terminated by a null ('\0') character. Therefore, the string functions (like strlen()) from the standard libary can be used.

  • Yes, that appears to be so!

    The 'extern' keyword in 'C' is equivalent to EXTERN in some assemblers; there is no equivalent of PUBLIC - because all file-scope symbols are automatically "public" unless specified otherwise.

    As already noted, this is standard 'C' stuff - nothing specifically to do with ARM and Keil - so any decent 'C' textbook should help.

    eg, see:
    http://www.keil.com/books/
    publications.gbdirect.co.uk/.../
    www.amazon.co.uk/.../ref=nb_ss_1_8

    You need to understand the difference between a declaration and a definition:

    Your global symbol must be defined exactly once - it is the definition which causes memory space to be allocated, and any initialiser to be applied.

    Your global symbol may be declared as often as required - it simply informs the compiler that a definition will be provided somewhere else, and gives the compiler sufficient information to use (not create) the thing.

    In my example, the AAA.c file provides the definition, and the cmd.h header provides the declaration;

    The cmd.h header can be included in as many files as need access to the string - such as BBB.c

    The reason for including the cmd.h header in AAA.c is to enable the compiler to detect that the declaration (in the header) matches the definition (in the .c file).

  • Also possible to do:

    const char my_string[] = "hello world!";
    const size_t my_string_size = sizeof(my_string);
    
    extern const char my_string[];
    extern const size_t my_string_size;