Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

struct look up table using string pointers issue

Tags:

c

I have written the following code:

unsigned char *cPtr[] =
{
    "First",
    "Second",
    "Third"
};

typedef struct
{
    int a;
    char *lut;  /* or char lut[20]*/
}Grp_t;

const Grp_t Grp_st[]=
{
    { 0, cPtr[0] },
    { 1, cPtr[1] },
    { 2, cPtr[2] }
};

When I try to compile this code I got the following error:

error: initializer element is not constant

error: (near initialization for 'Grp_st[0].lut[0]')

But when I replace *cPtr[] by cPtr[][16] as

unsigned char cPtr[][16] =
{
    "First",
    "Second",
    "Third"
};

I am able to successfully compile the code.

Please can any one explain me the concept which I am missing here.

like image 885
Tinchu Avatar asked Jul 28 '16 11:07

Tinchu


2 Answers

It is the limitation of C.

6.7.8.4 Initialization:

All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.

And 6.6.9 Constant expressions:

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.

If you can change the code to make Grp_st not of static storage duration it compiles:

#include <stdio.h>
const char *cPtr[] =
{
    "First",
    "Second",
    "Third"
};

typedef struct
{
    int a;
    const char *lut;
} Grp_t;


int main(void) {
    Grp_t Grp_st[]= {
    { 0, cPtr[0] },
    { 1, cPtr[1] },
    { 2, cPtr[2] }
    };
    return 0;
}

In the second case you managed to compile the code because you didn't access array element at given index, but only a pointer (in case of char cPtr[][16], the cPtr[0] gives address of the first array of 16 characters and cPtr[0] decays to type char * in expression) - therefore you didn't violate the 6.6.9 rule.

like image 154
4pie0 Avatar answered Oct 18 '22 12:10

4pie0


Initializer for a static object must be constant1.

Since you're trying to initialize a member of a static object, the member having the type pointer to char, you need an address constant2.

cPtr[0] is not an address constant because the value of the object cPtr is accessed while trying to create this address constant3.

On the other hand, cStr[0] doesn't access any value of the object cStr. The expression cStr[0] is identical to &cStr[0][0], which clearly doesn't access the value, but only the address to that value.


1 (Quoted from: ISO/IEC 9899:201x 6.7.9 Initialization 4)
All the expressions in an initializer for an object that has static or thread storage duration shall be constant expressions or string literals.

2 (Quoted from: ISO/IEC 9899:201x 6.6 Constant expressions 9)
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.

3 but the value of an object shall not be accessed by use of these operators.

like image 43
2501 Avatar answered Oct 18 '22 14:10

2501