0

I have been looking at c pointer to array of structs , and trying to apply it to my example.

I arrived at this code snippet, which compiles fine:

#include <stdio.h>

enum test_e {
    eONE,
    eTWO,
    eTHREE,
};
typedef enum test_e test_t;

#define NUMITEMS 12
extern test_t my_arr[NUMITEMS];

test_t (*my_arr_ptr)[NUMITEMS];

test_t my_arr[NUMITEMS] = { 0 };


int main()
{
    my_arr_ptr = &my_arr;
    printf("Hello World %p\n", my_arr_ptr);

    return 0;
}

In the above snippet, we have an assignment of my_arr_ptr variable, to the address of my_arr variable (using the "address of " operator, ampersand &).

However, what I would like to do is to initialize my_arr_ptr variable to the address of my_arr variable - which I'd think is possible, given that after the line test_t my_arr[NUMITEMS] = { 0 }; the compiler should "know" an address and size of my_arr.

However, if I try this:

#include <stdio.h>

enum test_e {
    eONE,
    eTWO,
    eTHREE,
};
typedef enum test_e test_t;

#define NUMITEMS 12
extern test_t my_arr[NUMITEMS];

test_t (*my_arr_ptr)[NUMITEMS];

test_t my_arr[NUMITEMS] = { 0 };

my_arr_ptr = &my_arr;

int main()
{
    //my_arr_ptr = &my_arr;
    printf("Hello World %p\n", my_arr_ptr);

    return 0;
}

... this fails with:

Compilation failed due to following error(s).

main.c:25:1: warning: data definition has no type or storage class
   25 | my_arr_ptr = &my_arr;
      | ^~~~~~~~~~
main.c:25:1: warning: type defaults to ‘int’ in declaration of ‘my_arr_ptr’ [-Wimplicit-int]
main.c:25:1: error: conflicting types for ‘my_arr_ptr’; have ‘int’
main.c:21:10: note: previous declaration of ‘my_arr_ptr’ with type ‘test_t (*)[12]’ {aka ‘enum test_e (*)[12]’}
   21 | test_t (*my_arr_ptr)[NUMITEMS];
      |          ^~~~~~~~~~
main.c:25:14: warning: initialization of ‘int’ from ‘test_t (*)[12]’ {aka ‘enum test_e (*)[12]’} makes integer from pointer without a cast [-Wint-conversion]
   25 | my_arr_ptr = &my_arr;
      |              ^
main.c:25:14: error: initializer element is not computable at load time
main.c: In function ‘main’:
main.c:30:26: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘int’ [-Wformat=]
   30 |     printf("Hello World %p\n", my_arr_ptr);
      |                         ~^     ~~~~~~~~~~
      |                          |     |
      |                          |     int
      |                          void *
      |                         %d

As far as I can see, "warning: data definition has no type or storage class" occurs:

because you can't execute code outside functions
(Why am I getting this error: "data definition has no type or storage class"?)

So, then, is the getting of "address of" considered "code" in C, so I cannot use it outside functions?

If so, how come I can use "address of" operator "outside functions" in the snippet below, which also compiles fine?:

#include <stdio.h>

void func_one(void) {
    printf("func_one\n");
}

void func_two(void) {
    printf("func_two\n");
}

void* funcs_arr[2] = { &func_one, &func_two  }; 

int main()
{
    printf("Hello World %p\n", funcs_arr[0]);

    return 0;
}
sdbbs
  • 4,270
  • 5
  • 32
  • 87
  • You can't have an expression like `my_arr_ptr = &my_arr;` outside of any function. All you can do is define variables (possibly with initialisers). – pmacfarlane Aug 20 '23 at 07:35
  • Thanks @pmacfarlane - how can I then define a variable of a pointer type, and initialize it to the address of another variable? – sdbbs Aug 20 '23 at 07:36
  • You probably should not use any global variables in the first place. They only cause pain and tears. – n. m. could be an AI Aug 20 '23 at 07:39
  • Probably `test_t *my_arr_ptr = my_arr;`. Your use of brackets is weird and looks like you're trying to do something like function pointers. – pmacfarlane Aug 20 '23 at 07:40
  • `my_arr_ptr = &my_arr` is not initialization in terms of the C standard. It is **assignment**, and assignments (and other kinds of expressions, as pointed out by the first comment) are never allowed in global scope. – Weijun Zhou Aug 20 '23 at 07:42
  • 1
    @pmacfarlane, the syntax is perfectly fine. Those are pointer to the whole arrays, a useful but poorly communicated feature of C language. – tstanisl Aug 20 '23 at 07:42
  • It seems a bit weird to want the address of the array. Are you going to change it to be something else? 99% of the time you want the address of the first member of the array. You seem to be a level of indirection too deep. – pmacfarlane Aug 20 '23 at 07:51

1 Answers1

2

The global variables are initialized at their definition. Just do:

extern test_t my_arr[NUMITEMS];

test_t (*my_arr_ptr)[NUMITEMS] = &my_arr;

Addresses of global objects are constant expressions and they can be used to initialize other global objects. See 6.6p7:

More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

  • an arithmetic constant expression,
  • a null pointer constant,
  • an address constant, or
  • an address constant for a complete object type plus or minus an integer constant expression.

The definition of "address constant" can be found at 6.6p9:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

tstanisl
  • 13,520
  • 2
  • 25
  • 40
  • Thanks so much - it works great! Amazingly - there is the solution, I've tried it it works, there is the explanation as well, I'm looking at it - and still I have difficulties wrapping my head around this (as in, how do I remember this, so I don't make the same mistake the next time `:)`). I guess I'll have to meditate on this answer a bit more `:)` – sdbbs Aug 20 '23 at 07:48