Problem with enums, const char* and structs

Discussion in 'C Programming' started by Esash, Oct 31, 2012.

  1. Esash

    Esash Guest

    Hello all,

    I am trying to compile this code with gcc. I wrote this sample code to test this pattern so that I can incorporate the same pattern in my project. But I am not able to compile this code. Here is the code.

    #include <stdio.h>

    #define EK "1"
    #define DO "2"

    const char *num[] = { EK, DO };

    typedef enum data_t_ {
    ONE,
    TWO,
    } data_t;

    typedef struct dat_t {
    char *ptr;
    int len;
    } dat_t;

    const dat_t *dat[] = {
    { num[ONE], sizeof(num[ONE]) },
    { num[TWO], sizeof(num[TWO]) },
    };

    int main()
    {
    int i;
    for ( i = 0; i < 2; i++ ) {
    printf("%s\t%d\n", dat->ptr, dat->len);
    }
    return 0;
    }

    I get the following errors :

    index.c:19:2: warning: braces around scalar initializer [enabled by default]
    index.c:19:2: warning: (near initialization for 'dat[0]') [enabled by default]
    index.c:19:2: error: initializer element is not constant
    index.c:19:2: error: (near initialization for 'dat[0]')
    index.c:19:2: warning: excess elements in scalar initializer [enabled by default
    ]
    index.c:19:2: warning: (near initialization for 'dat[0]') [enabled by default]
    index.c:20:2: warning: braces around scalar initializer [enabled by default]
    index.c:20:2: warning: (near initialization for 'dat[1]') [enabled by default]
    index.c:20:2: error: initializer element is not constant
    index.c:20:2: error: (near initialization for 'dat[1]')
    index.c:20:2: warning: excess elements in scalar initializer [enabled by default
    ]
    index.c:20:2: warning: (near initialization for 'dat[1]') [enabled by default]

    Please help.

    Thanks,
    Esash
     
    Esash, Oct 31, 2012
    #1
    1. Advertising

  2. Esash <> writes:

    > I am trying to compile this code with gcc. I wrote this sample code to
    > test this pattern so that I can incorporate the same pattern in my
    > project. But I am not able to compile this code. Here is the code.
    >
    > #include <stdio.h>
    >
    > #define EK "1"
    > #define DO "2"
    >
    > const char *num[] = { EK, DO };
    >
    > typedef enum data_t_ {
    > ONE,
    > TWO,
    > } data_t;
    >
    > typedef struct dat_t {
    > char *ptr;
    > int len;
    > } dat_t;
    >
    > const dat_t *dat[] = {
    > { num[ONE], sizeof(num[ONE]) },
    > { num[TWO], sizeof(num[TWO]) },
    > };


    One problem (probably not related to what you are trying to do) is that
    you've got a spurious * there. If you really do want an array of
    pointer to dat_t you will another level of initialisation.

    Another detail is that sizeof num[ONE] is the size of a pointer and
    that's probably not what you really want.

    But the "main" problem is that num[ONE] does not meet the definition of
    an allowable address constant. Basically, you can't access an array
    element to get an address constant. The rules are a little fiddly but
    for reference I've appended the paragraph below.

    It's not clear what the best course of action is because I am not sure
    what the essential elements are. You've not made any of the data static
    so I have to assume that everything is being accessed from everywhere
    (though I know that's probably not what you intended).

    You make be happy with:

    const dat_t dat[] = {
    { EK, sizeof EK },
    { DO, sizeof DO },
    };

    From the recent C11 draft (it did not change from C99):

    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.

    <snip>
    --
    Ben.
     
    Ben Bacarisse, Oct 31, 2012
    #2
    1. Advertising

  3. Esash

    Joe Pfeiffer Guest

    Esash <> writes:

    > Hello all,
    >
    > I am trying to compile this code with gcc. I wrote this sample code to test this pattern so that I can incorporate the same pattern in my project. But I am not able to compile this code. Here is the code.
    >
    > #include <stdio.h>
    >
    > #define EK "1"
    > #define DO "2"
    >
    > const char *num[] = { EK, DO };
    >
    > typedef enum data_t_ {
    > ONE,
    > TWO,
    > } data_t;
    >
    > typedef struct dat_t {
    > char *ptr;
    > int len;
    > } dat_t;
    >
    > const dat_t *dat[] = {
    > { num[ONE], sizeof(num[ONE]) },
    > { num[TWO], sizeof(num[TWO]) },
    > };
    >
    > int main()
    > {
    > int i;
    > for ( i = 0; i < 2; i++ ) {
    > printf("%s\t%d\n", dat->ptr, dat->len);
    > }
    > return 0;
    > }
    >
    > I get the following errors :
    >
    > index.c:19:2: warning: braces around scalar initializer [enabled by default]
    > index.c:19:2: warning: (near initialization for 'dat[0]') [enabled by default]
    > index.c:19:2: error: initializer element is not constant
    > index.c:19:2: error: (near initialization for 'dat[0]')
    > index.c:19:2: warning: excess elements in scalar initializer [enabled by default
    > ]
    > index.c:19:2: warning: (near initialization for 'dat[0]') [enabled by default]
    > index.c:20:2: warning: braces around scalar initializer [enabled by default]
    > index.c:20:2: warning: (near initialization for 'dat[1]') [enabled by default]
    > index.c:20:2: error: initializer element is not constant
    > index.c:20:2: error: (near initialization for 'dat[1]')
    > index.c:20:2: warning: excess elements in scalar initializer [enabled by default
    > ]
    > index.c:20:2: warning: (near initialization for 'dat[1]') [enabled by default]


    You've declared dat[] as an array of pointers to dat_t, but are
    initializing the array as if it were an array of dat_t. Changing the
    declaration and initialization to

    const dat_t dat[] = {
    { num[ONE], sizeof(num[ONE]) },
    { num[TWO], sizeof(num[TWO]) },
    };

    will clear up that problem, but will expose other errors.

    Something that I notice isn't an error per se, but is likely to cause
    significant confusion, is in your data_t_ enumeration -- ONE will have
    the value 0, and TWO will have the value 1. Also, in a program longer
    than about 10 lines, having various types, enums, and variables with
    names data_t_, data_t, dat_t, and dat will cause you to pull your hair
    out trying to figure out your own code.
     
    Joe Pfeiffer, Oct 31, 2012
    #3
  4. Esash

    Esash Guest

    On Wednesday, October 31, 2012 7:28:40 PM UTC+5:30, Ben Bacarisse wrote:
    > Esash <> writes:
    >
    >
    >
    > > I am trying to compile this code with gcc. I wrote this sample code to

    >
    > > test this pattern so that I can incorporate the same pattern in my

    >
    > > project. But I am not able to compile this code. Here is the code.

    >
    > >

    >
    > > #include <stdio.h>

    >
    > >

    >
    > > #define EK "1"

    >
    > > #define DO "2"

    >
    > >

    >
    > > const char *num[] = { EK, DO };

    >
    > >

    >
    > > typedef enum data_t_ {

    >
    > > ONE,

    >
    > > TWO,

    >
    > > } data_t;

    >
    > >

    >
    > > typedef struct dat_t {

    >
    > > char *ptr;

    >
    > > int len;

    >
    > > } dat_t;

    >
    > >

    >
    > > const dat_t *dat[] = {

    >
    > > { num[ONE], sizeof(num[ONE]) },

    >
    > > { num[TWO], sizeof(num[TWO]) },

    >
    > > };

    >
    >
    >
    > One problem (probably not related to what you are trying to do) is that
    >
    > you've got a spurious * there. If you really do want an array of
    >
    > pointer to dat_t you will another level of initialisation.
    >
    >
    >
    > Another detail is that sizeof num[ONE] is the size of a pointer and
    >
    > that's probably not what you really want.
    >
    >
    >
    > But the "main" problem is that num[ONE] does not meet the definition of
    >
    > an allowable address constant. Basically, you can't access an array
    >
    > element to get an address constant. The rules are a little fiddly but
    >
    > for reference I've appended the paragraph below.
    >
    >
    >
    > It's not clear what the best course of action is because I am not sure
    >
    > what the essential elements are. You've not made any of the data static
    >
    > so I have to assume that everything is being accessed from everywhere
    >
    > (though I know that's probably not what you intended).
    >
    >
    >
    > You make be happy with:
    >
    >
    >
    > const dat_t dat[] = {
    >
    > { EK, sizeof EK },
    >
    > { DO, sizeof DO },
    >
    > };
    >
    >
    >
    > From the recent C11 draft (it did not change from C99):
    >
    >
    >
    > 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.
    >
    >
    >
    > <snip>
    >
    > --
    >
    > Ben.


    Thanks a lot Ben. I got the point why I got those errors. But actually whatI need is the initialization of char* member here :

    const dat_t *dat[] = {
    { num[ONE], sizeof(num[ONE]) },
    { num[TWO], sizeof(num[TWO]) },
    };

    As you said, this had to be :

    const dat_t dat[] = {
    { num[ONE], strlen(num[ONE]) },
    { num[TWO], strlen(num[TWO]) },
    };

    But the problem lies in num[ONE] and num[TWO]. So, is there no way to initialize a structure member with a variable even if it is a const ? I understand that the compiler cannot be sure of such initializations since they might be subject to changes in the future. But any workaround ? Here is the modified code..

    const char *num[] = { "this" , "that" };

    typedef enum data_t_ {
    ONE,
    TWO,
    } data_t;

    typedef struct dat_t {
    char *ptr;
    int len;
    } dat_t;

    const dat_t dat[2] = {
    { num[ONE], strlen(num[ONE])},
    { num[ONE], strlen(num[TWO])},
    };

    int main()
    {
    int i;
    for (i=0; i<2; i++) {
    printf("%s\t%d\n", dat.ptr, dat.len);
    }
    return 0;
    }
     
    Esash, Oct 31, 2012
    #4
  5. Esash

    Esash Guest

    On Wednesday, October 31, 2012 10:57:57 PM UTC+5:30, Esash wrote:
    > On Wednesday, October 31, 2012 7:28:40 PM UTC+5:30, Ben Bacarisse wrote:
    >
    > > Esash <> writes:

    >
    > >

    >
    > >

    >
    > >

    >
    > > > I am trying to compile this code with gcc. I wrote this sample code to

    >
    > >

    >
    > > > test this pattern so that I can incorporate the same pattern in my

    >
    > >

    >
    > > > project. But I am not able to compile this code. Here is the code.

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > #include <stdio.h>

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > #define EK "1"

    >
    > >

    >
    > > > #define DO "2"

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > const char *num[] = { EK, DO };

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > typedef enum data_t_ {

    >
    > >

    >
    > > > ONE,

    >
    > >

    >
    > > > TWO,

    >
    > >

    >
    > > > } data_t;

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > typedef struct dat_t {

    >
    > >

    >
    > > > char *ptr;

    >
    > >

    >
    > > > int len;

    >
    > >

    >
    > > > } dat_t;

    >
    > >

    >
    > > >

    >
    > >

    >
    > > > const dat_t *dat[] = {

    >
    > >

    >
    > > > { num[ONE], sizeof(num[ONE]) },

    >
    > >

    >
    > > > { num[TWO], sizeof(num[TWO]) },

    >
    > >

    >
    > > > };

    >
    > >

    >
    > >

    >
    > >

    >
    > > One problem (probably not related to what you are trying to do) is that

    >
    > >

    >
    > > you've got a spurious * there. If you really do want an array of

    >
    > >

    >
    > > pointer to dat_t you will another level of initialisation.

    >
    > >

    >
    > >

    >
    > >

    >
    > > Another detail is that sizeof num[ONE] is the size of a pointer and

    >
    > >

    >
    > > that's probably not what you really want.

    >
    > >

    >
    > >

    >
    > >

    >
    > > But the "main" problem is that num[ONE] does not meet the definition of

    >
    > >

    >
    > > an allowable address constant. Basically, you can't access an array

    >
    > >

    >
    > > element to get an address constant. The rules are a little fiddly but

    >
    > >

    >
    > > for reference I've appended the paragraph below.

    >
    > >

    >
    > >

    >
    > >

    >
    > > It's not clear what the best course of action is because I am not sure

    >
    > >

    >
    > > what the essential elements are. You've not made any of the data static

    >
    > >

    >
    > > so I have to assume that everything is being accessed from everywhere

    >
    > >

    >
    > > (though I know that's probably not what you intended).

    >
    > >

    >
    > >

    >
    > >

    >
    > > You make be happy with:

    >
    > >

    >
    > >

    >
    > >

    >
    > > const dat_t dat[] = {

    >
    > >

    >
    > > { EK, sizeof EK },

    >
    > >

    >
    > > { DO, sizeof DO },

    >
    > >

    >
    > > };

    >
    > >

    >
    > >

    >
    > >

    >
    > > From the recent C11 draft (it did not change from C99):

    >
    > >

    >
    > >

    >
    > >

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

    >
    > >

    >
    > >

    >
    > >

    >
    > > <snip>

    >
    > >

    >
    > > --

    >
    > >

    >
    > > Ben.

    >
    >
    >
    > Thanks a lot Ben. I got the point why I got those errors. But actually what I need is the initialization of char* member here :
    >
    >
    >
    > const dat_t *dat[] = {
    >
    > { num[ONE], sizeof(num[ONE]) },
    >
    > { num[TWO], sizeof(num[TWO]) },
    >
    > };
    >
    >
    >
    > As you said, this had to be :
    >
    >
    >
    > const dat_t dat[] = {
    >
    > { num[ONE], strlen(num[ONE]) },
    >
    > { num[TWO], strlen(num[TWO]) },
    >
    > };
    >
    >
    >
    > But the problem lies in num[ONE] and num[TWO]. So, is there no way to initialize a structure member with a variable even if it is a const ? I understand that the compiler cannot be sure of such initializations since they might be subject to changes in the future. But any workaround ? Here is the modified code..
    >
    >
    >
    > const char *num[] = { "this" , "that" };
    >
    >
    >
    > typedef enum data_t_ {
    >
    > ONE,
    >
    > TWO,
    >
    > } data_t;
    >
    >
    >
    > typedef struct dat_t {
    >
    > char *ptr;
    >
    > int len;
    >
    > } dat_t;
    >
    >
    >
    > const dat_t dat[2] = {
    >
    > { num[ONE], strlen(num[ONE])},
    >
    > { num[ONE], strlen(num[TWO])},
    >
    > };
    >
    >
    >
    > int main()
    >
    > {
    >
    > int i;
    >
    > for (i=0; i<2; i++) {
    >
    > printf("%s\t%d\n", dat.ptr, dat.len);
    >
    > }
    >
    > return 0;
    >
    > }


    And the problems posed here with this revised code are the same as Joe's quoted in his reply.

    index.c:54:2: error: initializer element is not constant
    index.c:54:2: error: (near initialization for 'dat[0].ptr')
    index.c:55:2: error: initializer element is not constant
    index.c:55:2: error: (near initialization for 'dat[1].ptr')

    So is there any workaround ? I got the point that replacing #defined valueswould solve the problem but in my case I cannot give the #defined values since the actual value in place of num[ONE] and num[TWO] are functions. These are big functions which cannot be written as a macro or inline functions.So they cannot be #defined.

    Please advise.

    Thanks,
    Esash
     
    Esash, Oct 31, 2012
    #5
  6. Esash <> writes:
    > I am trying to compile this code with gcc. I wrote this sample code to
    > test this pattern so that I can incorporate the same pattern in my
    > project. But I am not able to compile this code. Here is the code.
    >
    > #include <stdio.h>
    >
    > #define EK "1"
    > #define DO "2"
    >
    > const char *num[] = { EK, DO };
    >
    > typedef enum data_t_ {
    > ONE,
    > TWO,
    > } data_t;
    >
    > typedef struct dat_t {
    > char *ptr;
    > int len;
    > } dat_t;


    None of the following is relevant to the problem you're asking about.

    For an enum, struct, or union type, there's really no benefit in using
    distinct identifiers for the tag and the typedef. You're using
    different identifiers "data_t_" and "dat_t" for your enum type, and the
    same identifier, "dat_t" for your struct type. Since tags are in a
    separate namespace, appending "_" to get a unique name is neither
    necessary nor helpful.

    If you want to have a single identifier as the name of your type, you
    can just omit the tag:

    typedef enum { ONE, TWO } data_t;

    Or you can omit the typedef:

    enum data_t { ONE, TWO };

    and refer to the type as "enum data_t". The same applies to struct
    and union types, except that things get a little more complicated
    for self-referential types (e.g., if a struct type contains a
    pointer to itself).

    And even for this example, using names like "dat_t" and "data_t" is
    unnecessarily confusing.

    [...]

    > int main()


    I suggest writing this as "int main(void)", since it's more explicit.

    Another thing: Google Groups has completely messed up its Usenet
    interface. In your followups in this thread, quoted text is
    double-spaced, or even quadruple- or octuple-spaced. I don't know
    what Google did to cause this problem, or why, but you can work
    around it by copy-and-pasting your article into your favorite text
    editor, deleting the extra lines, and then copy-and-pasting it back
    into your browser before posting. It's also helpful to wrap your
    lines to 72 columns or so. Or you could consider using a real Usenet
    server (I use news.eternal-september.org) and client (I use Gnus,
    which runs inside Emacs; there are a number of other free clients).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Will write code for food.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Oct 31, 2012
    #6
  7. On Wed, 31 Oct 2012 10:27:57 -0700 (PDT), Esash
    <> wrote:

    >
    >Thanks a lot Ben. I got the point why I got those errors. But actually what I need is the initialization of char* member here :
    >
    >const dat_t *dat[] = {
    > { num[ONE], sizeof(num[ONE]) },
    > { num[TWO], sizeof(num[TWO]) },
    >};
    >
    >As you said, this had to be :
    >
    >const dat_t dat[] = {
    > { num[ONE], strlen(num[ONE]) },
    > { num[TWO], strlen(num[TWO]) },
    >};
    >
    >But the problem lies in num[ONE] and num[TWO]. So, is there no way to initialize a structure member with a variable even if it is a const ? I understand that the compiler cannot be sure of such initializations since they might be subject to changes in the future. But any workaround ? Here is the modified code..
    >
    >const char *num[] = { "this" , "that" };
    >
    >typedef enum data_t_ {
    > ONE,
    > TWO,
    >} data_t;
    >
    >typedef struct dat_t {
    > char *ptr;
    > int len;
    >} dat_t;
    >
    >const dat_t dat[2] = {
    > { num[ONE], strlen(num[ONE])},
    > { num[ONE], strlen(num[TWO])},
    >};
    >
    >int main()
    >{
    > int i;
    > for (i=0; i<2; i++) {
    > printf("%s\t%d\n", dat.ptr, dat.len);
    > }
    > return 0;
    >}


    First, you need to realize that const and constant are two different
    things. Even though the value of num[0] is const, it is not a compile
    time constant. This is the same reason
    const int x = 2;
    static int y[x];
    cannot be used.

    Other than the fact that you are attempting to use num in the
    initialization of dat, is there any reason it needs to be at file
    scope or for that matter even exist? Could you use
    const dat_t dat[2] = {
    { "this", sizeof "this" -1},
    { "that", sizeof "that" -1},
    };

    If you really need num at file scope with external linkage, consider
    moving dat inside main. Once it no longer has static duration, you
    have a lot more flexibility with the initialization. If you need dat
    to be "global", add a global pointer to it that you assign in main.
    Other source files will still be able to access dat and as long as you
    don't call main recursively, it is effectively static. Something like

    const char *num[] = { "this" , "that" };

    typedef enum data_t_ {
    ONE,
    TWO,
    } data_t;

    typedef struct dat_t {
    char *ptr;
    int len;
    } dat_t;

    dat_t *dat_ptr; /* <================ */

    int main()
    {
    const dat_t dat[2] = {
    { num[ONE], strlen(num[ONE])},
    { num[ONE], strlen(num[TWO])},
    };

    int i;
    dat_ptr = dat; /* <================= */
    for (i=0; i<2; i++) {
    printf("%s\t%d\n", dat.ptr, dat.len);
    }
    return 0;
    }

    May I suggest that ONE being 0 and TWO being 1 is not the most
    readable choice you could make.

    --
    Remove del for email
     
    Barry Schwarz, Oct 31, 2012
    #7
  8. Esash

    James Kuyper Guest

    On 10/31/2012 01:27 PM, Esash wrote:
    > On Wednesday, October 31, 2012 7:28:40 PM UTC+5:30, Ben Bacarisse wrote:

    ....
    >> You make be happy with:
    >>
    >>
    >>
    >> const dat_t dat[] = {
    >>
    >> { EK, sizeof EK },
    >>
    >> { DO, sizeof DO },
    >>
    >> };
    >>
    >>
    >>
    >> From the recent C11 draft (it did not change from C99):
    >>
    >>
    >>
    >> 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.
    >>
    >>
    >>
    >> <snip>
    >>
    >> --
    >>
    >> Ben.

    >
    > Thanks a lot Ben. I got the point why I got those errors. But actually
    > what I need is the initialization of char* member here :


    Could you explain in more detail why you can't use Ben's suggestion?
    The char* member does get initialized with his suggestion.

    > const dat_t *dat[] = {
    > { num[ONE], sizeof(num[ONE]) },
    > { num[TWO], sizeof(num[TWO]) },
    > };
    >
    > As you said, this had to be :
    >
    > const dat_t dat[] = {
    > { num[ONE], strlen(num[ONE]) },
    > { num[TWO], strlen(num[TWO]) },
    > };
    >


    > But the problem lies in num[ONE] and num[TWO]. So, is there no way
    > to initialize a structure member with a variable even if it is a const ?


    Correct, at least for objects with static or thread storage duration.
    Note that strlen() is also a problem here, for the same reason - it's
    not a constant expression.

    > I understand that the compiler cannot be sure of such initializations > since they might be subject to changes in the future. But any workaround?


    The simplest solution is to give this array automatic storage duration,
    by defining it inside a function. The restriction that the initializers
    must be constant expressions applies only for objects with static or
    thread storage duration.

    If you need to refer to that array from multiple different functions,
    pass around a pointer to the first element of the array, rather than
    referring to the array directly. In general, I don't recommend using
    global variables. However, if you must use one, if you replaced the
    global array with a global pointer to the first element of an
    automatically allocated array array, most uses of the pointer would use
    the same exact syntax as for an array, so very little code would need to
    be re-written.

    If you need C90 compatibility, one work-around would be to remove the
    'const' from the declaration of dat, explicitly set the length of the
    array, and set the values explicitly, rather than using initialization
    syntax:

    dat[0].ptr = num[ONE];
    dat[0].len = strlen(dat[0].ptr);
    // etc.

    You can still pass the array around using a pointer that retains the
    'const', that you had to remove from 'dat' itself.

    > Here is the modified code..
    >
    > const char *num[] = { "this" , "that" };
    >
    > typedef enum data_t_ {
    > ONE,
    > TWO,
    > } data_t;
    >
    > typedef struct dat_t {
    > char *ptr;


    In most contexts, including this one, a string literal causes the
    creation of an anonymous char array, and has a value which is a pointer
    to the first element of that array. Code which attempts to modify any
    element of that array has undefined behavior. That's why you were right
    to declare 'num' using 'const'. However, since ptr will end up
    containing copies of those same pointers, it should also be declared as

    const char *ptr;

    so that any code which attempts to modify those arrays through that
    pointer will force the compiler to issue a diagnostic message.

    > int len;
    > } dat_t;
     
    James Kuyper, Oct 31, 2012
    #8
  9. Esash <> writes:

    > On Wednesday, October 31, 2012 10:57:57 PM UTC+5:30, Esash wrote:
    >> On Wednesday, October 31, 2012 7:28:40 PM UTC+5:30, Ben Bacarisse wrote:
    >>
    >> > Esash <> writes:

    >>
    >> >

    >>
    >> >

    >>
    >> >

    >>
    >> > > I am trying to compile this code with gcc. I wrote this sample code to

    >>
    >> >


    You might want to consider using another new reader; it's Google's
    awful interface that's adding all the extra blank lines. If that's not
    possible, please consider snipping some of your replies. You don't need
    all of this text to make the point below.

    <snip>
    > And the problems posed here with this revised code are the same as Joe's quoted in his reply.
    >
    > index.c:54:2: error: initializer element is not constant
    > index.c:54:2: error: (near initialization for 'dat[0].ptr')
    > index.c:55:2: error: initializer element is not constant
    > index.c:55:2: error: (near initialization for 'dat[1].ptr')
    >
    > So is there any workaround ?


    Not without more information. What can and can not be changed? How
    complex is the real situation?

    > I got the point that replacing #defined
    > values would solve the problem but in my case I cannot give the
    > #defined values since the actual value in place of num[ONE] and
    > num[TWO] are functions. These are big functions which cannot be
    > written as a macro or inline functions. So they cannot be #defined.


    I don't understand because you are being a little loose with your terms.
    Do you really mean the values are function, or do you mean function
    calls? When you say "in place of" surely you don't mean you posted code
    that uses array elements when the "real" situation does not? maybe you
    mean the values *in* num[ONE] and num[TWO] are the result of function
    calls? If so, the situation is even worse than the example you
    posted -- in C no functions can be called during the initialisation of a
    file-scope object. But, as I said, maybe that's not what you mean.

    But fear not: we all understand C so post the real code, not an
    approximation to it, and you will get more realistic answers. In
    addition, you need to say what can be sacrificed. If your code does not
    work, something has to change so what can be changed and what can't be?

    --
    Ben.
     
    Ben Bacarisse, Oct 31, 2012
    #9
  10. Esash

    James Kuyper Guest

    On 10/31/2012 01:32 PM, Esash wrote:
    > On Wednesday, October 31, 2012 10:57:57 PM UTC+5:30, Esash wrote:

    ....
    > And the problems posed here with this revised code are the same as
    > Joe's quoted in his reply.
    >
    > index.c:54:2: error: initializer element is not constant


    > index.c:54:2: error: (near initialization for 'dat[0].ptr')


    > index.c:55:2: error: initializer element is not constant


    > index.c:55:2: error: (near initialization for 'dat[1].ptr')
    >
    > So is there any workaround ? I got the point that replacing #defined
    > values would solve the problem but in my case I cannot give the
    > #defined values since the actual value in place of num[ONE] and
    > num[TWO] are functions. These are big functions which cannot be
    > written as a macro or inline functions. So they cannot be #defined.


    If the expressions you're actually using where you wrote num[ONE] and
    num[TWO] are actually the result of function calls, you certainly cannot
    use them to initialize a statically allocated array. I've already told
    you how you can deal with this, but I'll fill in the details below.

    I'll assume that the pointers returned by that function point to
    unmodifiable memory, just like num[ONE] and num[TWO]; if that's not the
    case, the first and third uses of 'const' below can be removed.

    I'll assume that you know the maximum number of elements in your array
    (that's implied by your use of enumerations constants in the
    initialization), and that you have a justified reason for needing global
    access to it (which seems less likely to be true). I recommend against
    using type names ending with _t, at least if your code might ever need
    to be ported to a POSIX-compliant system. POSIX has reserved all such
    names (other than those already reserved by C) for it's own use.

    data.h:
    enum {
    ZERO,
    ONE,
    NUM_DATA
    };

    typedef struct {
    const char *ptr;
    int len;
    } mydata;

    extern const mydata *data_list;

    main.c:
    #include <string.h>
    #include "data.h"
    extern const char*get_string(int);
    const mydata *data_list;

    int main(void)
    {
    const mydata data_array[NUM_DATA] = {
    {get_string(ZERO), strlen(get_string(ZERO)) },
    {get_string(ONE), strlen(get_string(ONE)) },
    };
    data_list = data_array;
    // The rest of your program
    return 0;
    }

    Any module that needs access to the array should #include "data.h", and
    access it through data_list.
     
    James Kuyper, Nov 1, 2012
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Santa
    Replies:
    1
    Views:
    1,128
    Mark A. Odell
    Jul 17, 2003
  2. Chris Hauxwell

    const structs in other structs

    Chris Hauxwell, Apr 23, 2004, in forum: C Programming
    Replies:
    6
    Views:
    565
    Chris Hauxwell
    Apr 27, 2004
  3. Replies:
    24
    Views:
    857
    Netocrat
    Oct 30, 2005
  4. lovecreatesbeauty
    Replies:
    1
    Views:
    1,099
    Ian Collins
    May 9, 2006
  5. Javier
    Replies:
    2
    Views:
    585
    James Kanze
    Sep 4, 2007
Loading...

Share This Page