arrayscif-statementdeclaration

extern variable prototype: comparison of array not equal to a null pointer is always true


while cleaning an old program GCC returned a warning that I could not understand. Here is a snippet:

#include <stdio.h>
#include <stdint.h>

extern int *foo[];

int main(void) {
    if (foo != NULL)
        printf("Foo is not null\n");
    return 0;
}
$ gcc -Wall main.c
main.c: In function 'main':
main.c:7:17: warning: the comparison will always evaluate as 'true' for the address of 'foo' will never be NULL [-Waddress]
    7 |         if (foo != NULL)
      |                 ^~
main.c:4:13: note: 'foo' declared here
    4 | extern int *foo[];
      |      

I then tried to change the prototype to extern int **foo;:

$ gcc -Wall main.c
/usr/bin/ld: /tmp/cciux1Df.o: warning: relocation against `foo' in read-only section `.text'
  1. As demonstrated here, without initialisation they should be considered the same. Why **foo (rightfully) fails to compile as an undefined reference, while GCC successfully compiles with *foo[]?

  2. What does the error relocation against 'foo' in read-only section '.text' really means as a warning?

Thanks.


Solution

  • The compiler tries to say you that this statement

    if (foo != NULL)
    

    does not make sense because an array always occupies memory and you declared an array

    extern int *foo[];.

    In the if statement the array designator foo is implicitly converted to pointer of the type int ** that points to the first element of the array (that is to the extent of memory occupied by the array). So it can not be equal to NULL.

    Pay attention to that you should define the array somewhere in this or other translation unit. Otherwise the linker can issue an error that the array is not defined. Because the above declaration of the array is not its definition and not its tentative definition.