const array declaration

Discussion in 'C Programming' started by herbertF, Feb 9, 2004.

  1. herbertF

    herbertF Guest

    Hi guys,

    In a program (not my own) I encountered the declaration of a constant
    pointer to an array consisting of two other const pointers to arrays.
    Not quite sure why they do it so complicated, but is it legal? Most
    compilers accept it, but one doesn't recognize the rhs as a constant.
    What are the requirements for the rhs in the declaration of a const
    pointer? Is the following program legal C?

    int main(int argc, char *argv[]) {
    const char *a[] = {"A"};
    const char *b[] = {"B"};
    const char **z[] = {a, b}; /* this is the statement in question */
    return (0);
    }

    The error message is
    "t.c", line 4: error: initialization: constant expression is expected
    for variable: `z'

    Thanks in advance,

    Herbert
    herbertF, Feb 9, 2004
    #1
    1. Advertising

  2. herbertF wrote:

    > In a program (not my own) I encountered the declaration of a constant
    > pointer to an array consisting of two other const pointers to arrays.
    > Not quite sure why they do it so complicated, but is it legal? Most
    > compilers accept it, but one doesn't recognize the rhs as a constant.
    > What are the requirements for the rhs in the declaration of a const
    > pointer? Is the following program legal C?
    >
    > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};
    > const char **z[] = {a, b}; /* this is the statement in question */
    > return (0);
    > }
    >
    > The error message is
    > "t.c", line 4: error: initialization:
    > constant expression is expected for variable: `z'


    Let me try:

    > cat main.c

    int main(int argc, char* argv[]) {
    const char* const a[] = {"A"};
    const char* const b[] = {"B"};
    const char* const *z[] = {a, b};
    return 0;
    }

    > gcc -Wall -std=c99 -pedantic -o main main.c

    main.c: In function `main':
    main.c:6: warning: unused variable `z'

    It seems to work just fine.
    E. Robert Tisdale, Feb 9, 2004
    #2
    1. Advertising

  3. herbertF

    Tom St Denis Guest

    "herbertF" <> wrote in message
    news:...
    > Hi guys,
    >
    > In a program (not my own) I encountered the declaration of a constant
    > pointer to an array consisting of two other const pointers to arrays.
    > Not quite sure why they do it so complicated, but is it legal? Most
    > compilers accept it, but one doesn't recognize the rhs as a constant.
    > What are the requirements for the rhs in the declaration of a const
    > pointer? Is the following program legal C?
    >
    > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};
    > const char **z[] = {a, b}; /* this is the statement in question */
    > return (0);
    > }


    Your const was in the wrong spot.

    int main(int argc, char *argv[]) {
    char const *a[] = {"A"};
    char const *b[] = {"B"};
    char const **z[] = {a, b}; /* this is the statement in question */
    return (0);
    }

    Works just fine.

    Tom
    Tom St Denis, Feb 9, 2004
    #3
  4. herbertF

    Eric Sosman Guest

    herbertF wrote:
    >
    > Hi guys,
    >
    > In a program (not my own) I encountered the declaration of a constant
    > pointer to an array consisting of two other const pointers to arrays.
    > Not quite sure why they do it so complicated, but is it legal? Most
    > compilers accept it, but one doesn't recognize the rhs as a constant.
    > What are the requirements for the rhs in the declaration of a const
    > pointer? Is the following program legal C?
    >
    > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};
    > const char **z[] = {a, b}; /* this is the statement in question */
    > return (0);
    > }
    >
    > The error message is
    > "t.c", line 4: error: initialization: constant expression is expected
    > for variable: `z'


    The complaining compiler is correct: `a' and `b' are not
    constant expressions.
    Despite the spelling, `const' is not
    "constant."

    If you think about it in a wider context, you'll see why
    `a' and `b' are not constant. Here's a recursive function
    with a similar construct, to help show what's happening:

    void func(int x) {
    const char *a[] = { "A", "B" };
    if (0 <= x && x < 2) {
    a[x] = "X";
    printf ("func(%d): a[0] = %s, a[1] = %s\n",
    x, a[0], a[1]);
    func (x + 1);
    printf ("func(%d): a[0] = %s, a[1] = %s\n",
    x, a[0], a[1]);
    }
    else {
    printf ("func(%d): nothing to do\n", x);
    }
    }

    If you call this function with `func(0)', the output will be

    func(0): a[0] = X, a[1] = B
    func(1): a[0] = A, a[1] = X
    func(2): nothing to do
    func(1): a[0] = A, a[1] = X
    func(0): a[0] = X, a[1] = B

    This shows that two different `a' arrays exist: one in
    the outer func(0) invocation, and another in the inner func(1).
    You can see that there must be more than one `a[]' because
    when the outer func(0) executes `a[0] = "X"' the value of `a[0]'
    in the inner func(1) is not affected; likewise when the inner
    func(1) sets `a[1] = "X"' it does not change `a[1]' in the
    outer func(0). Each `a[]' array comes into existence when its
    invocation of func() begins, and ceases to exist when its own
    func() returns. Thus, even though `a' is just one identifier,
    it designates different array objects at different times and
    is therefore not a constant.

    If you changed the function to declare the array as

    static const char *a[] = { "A", "B" };

    you would get a different output altogether:

    func(0): a[0] = X, a[1] = B
    func(1): a[0] = X, a[1] = X
    func(2): nothing to do
    func(1): a[0] = X, a[1] = X
    func(0): a[0] = X, a[1] = X

    In this case there is only one `a[]' array, and any changes
    made to it in one func() invocation are seen in the other. The
    lifetime of this single `a[]' is no longer tied to the execution
    of its containing block; this `a[]' comes into existence before
    the program starts executing and continues to exist until the
    program terminates. In this case, `a' *is* a constant, because
    the identifier refers to just one object for the entire time the
    program is running. If the one-and-only-one semantics make sense
    for your original program, perhaps the cure is to add the `static'
    qualifier.

    By the way, the non-complaining compilers are not in error.
    A compiler is *permitted* to allow non-constant initializers in
    addition to the constant initializers required by the Standard.

    --
    Eric Sosman, Feb 9, 2004
    #4
  5. herbertF

    Tom St Denis Guest

    "Eric Sosman" <> wrote in message
    news:...

    > The complaining compiler is correct: `a' and `b' are not
    > constant expressions.
    > Despite the spelling, `const' is not
    > "constant."


    Yes it is. There is just a diff between

    const char *varname;

    and

    char const *varname;

    The former means the values in varname[...] are constant. E.g.

    varname[0] = 'a';

    will produce a warning.

    In the latter the actual pointer "varname" is constant so

    varname = &somebuf;

    will produce a warning while

    varname[0] = 'a';

    will not.

    const char const *varname;

    will make both constant.

    Tom
    Tom St Denis, Feb 9, 2004
    #5
  6. Tom St Denis <> wrote:

    > "Eric Sosman" <> wrote in message
    > news:...


    >> The complaining compiler is correct: `a' and `b' are not
    >> constant expressions.
    >> Despite the spelling, `const' is not
    >> "constant."


    > Yes it is. There is just a diff between


    > const char *varname;


    > and


    > char const *varname;


    These two forms are absolutely equivalent. For the latter you must
    be thinking about something like

    char * const varname;

    > The former means the values in varname[...] are constant. E.g.


    > varname[0] = 'a';


    > will produce a warning.


    .... and invoke undefined behavior since varname is not
    pointing at anything, but I digress.

    > In the latter the actual pointer "varname" is constant so


    Not true. See my comment above.

    > const char const *varname;


    This is exactly equivalent to:

    const const char *varname;

    Which is obviously wrong. Again, what you obviously meant to write:

    const char * const varname;

    --
    Alex Monjushko ()
    Alex Monjushko, Feb 9, 2004
    #6
  7. herbertF

    Tom St Denis Guest

    "Alex Monjushko" <> wrote in message
    news:c08oiq$139a9a$-berlin.de...
    > Tom St Denis <> wrote:
    >
    > > "Eric Sosman" <> wrote in message
    > > news:...

    >
    > >> The complaining compiler is correct: `a' and `b' are not
    > >> constant expressions.
    > >> Despite the spelling, `const' is not
    > >> "constant."

    >
    > > Yes it is. There is just a diff between

    >
    > > const char *varname;

    >
    > > and

    >
    > > char const *varname;

    >
    > These two forms are absolutely equivalent. For the latter you must
    > be thinking about something like
    >
    > char * const varname;


    Yeah, oops.

    Tom
    Tom St Denis, Feb 9, 2004
    #7
  8. herbertF

    nrk Guest

    Tom St Denis wrote:

    >
    > "Eric Sosman" <> wrote in message
    > news:...
    >
    >> The complaining compiler is correct: `a' and `b' are not
    >> constant expressions.
    >> Despite the spelling, `const' is not
    >> "constant."

    >
    > Yes it is. There is just a diff between
    >


    Bad Tom!! "Here be dragons" :)

    > const char *varname;
    >
    > and
    >
    > char const *varname;
    >
    > The former means the values in varname[...] are constant. E.g.
    >


    Nope. Both mean exactly the same thing. Perhaps you wanted to show the
    difference between:
    const char *varname;
    and
    char * const varname;

    Former is a pointer to a const char, the latter a const pointer to char.

    > varname[0] = 'a';
    >
    > will produce a warning.
    >
    > In the latter the actual pointer "varname" is constant so
    >
    > varname = &somebuf;
    >
    > will produce a warning while
    >
    > varname[0] = 'a';
    >
    > will not.
    >
    > const char const *varname;
    >
    > will make both constant.
    >


    Nope. What you're looking for is:
    const char * const varname;

    Which makes varname a const pointer to const char.

    -nrk.

    > Tom


    --
    Remove devnull for email
    nrk, Feb 9, 2004
    #8
  9. Tom St Denis wrote:

    >
    > "Eric Sosman" <> wrote in message
    > news:...
    >
    >> The complaining compiler is correct: `a' and `b' are not
    >> constant expressions.
    >> Despite the spelling, `const' is not
    >> "constant."

    >
    > Yes it is. There is just a diff between
    >
    > const char *varname;
    >
    > and
    >
    > char const *varname;


    No, not really. Both mean: "varname is a pointer to const char".

    >
    > The former means the values in varname[...] are constant. E.g.
    >
    > varname[0] = 'a';
    >
    > will produce a warning.
    >
    > In the latter the actual pointer "varname" is constant so
    >
    > varname = &somebuf;
    >
    > will produce a warning while
    >
    > varname[0] = 'a';
    >
    > will not.
    >
    > const char const *varname;
    >
    > will make both constant.


    No.

    const char *varname;

    and

    char const *varname;

    both mean the same thing - a pointer to const char. If you want a const
    pointer to char, you need:

    char * const varname;

    --
    Richard Heathfield :
    "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
    C FAQ: http://www.eskimo.com/~scs/C-faq/top.html
    K&R answers, C books, etc: http://users.powernet.co.uk/eton
    Richard Heathfield, Feb 9, 2004
    #9
  10. herbertF

    Jack Klein Guest

    On Mon, 09 Feb 2004 19:10:46 GMT, "Tom St Denis"
    <> wrote in comp.lang.c:

    >
    > "herbertF" <> wrote in message
    > news:...
    > > Hi guys,
    > >
    > > In a program (not my own) I encountered the declaration of a constant
    > > pointer to an array consisting of two other const pointers to arrays.
    > > Not quite sure why they do it so complicated, but is it legal? Most
    > > compilers accept it, but one doesn't recognize the rhs as a constant.
    > > What are the requirements for the rhs in the declaration of a const
    > > pointer? Is the following program legal C?
    > >
    > > int main(int argc, char *argv[]) {
    > > const char *a[] = {"A"};
    > > const char *b[] = {"B"};
    > > const char **z[] = {a, b}; /* this is the statement in question */
    > > return (0);
    > > }

    >
    > Your const was in the wrong spot.
    >
    > int main(int argc, char *argv[]) {
    > char const *a[] = {"A"};
    > char const *b[] = {"B"};
    > char const **z[] = {a, b}; /* this is the statement in question */
    > return (0);
    > }
    >
    > Works just fine.
    >
    > Tom


    There is no difference at all between "const type" and "type const" in
    a declarator.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Feb 10, 2004
    #10
  11. herbertF

    Jack Klein Guest

    On Mon, 09 Feb 2004 19:43:36 GMT, "Tom St Denis"
    <> wrote in comp.lang.c:

    >
    > "Eric Sosman" <> wrote in message
    > news:...
    >
    > > The complaining compiler is correct: `a' and `b' are not
    > > constant expressions.
    > > Despite the spelling, `const' is not
    > > "constant."

    >
    > Yes it is. There is just a diff between
    >
    > const char *varname;
    >
    > and
    >
    > char const *varname;
    >
    > The former means the values in varname[...] are constant. E.g.
    >
    > varname[0] = 'a';
    >
    > will produce a warning.
    >
    > In the latter the actual pointer "varname" is constant so
    >
    > varname = &somebuf;
    >
    > will produce a warning while
    >
    > varname[0] = 'a';
    >
    > will not.
    >
    > const char const *varname;
    >
    > will make both constant.
    >
    > Tom


    Look on the bright side, Tom. I did this once in comp.lang.c, years
    ago, and had my *ss handed to me. I'll never make that particular
    mistake again. I doubt you will, either.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.contrib.andrew.cmu.edu/~ajo/docs/FAQ-acllc.html
    Jack Klein, Feb 10, 2004
    #11
  12. herbertF

    Richard Bos Guest

    (herbertF) wrote:

    > Thanks for the lengthy discussion, but it seems like the question is
    > still not anwered.


    Actually, it is.

    > What I've learnt from it so far is that the "const"
    > seems to refer to the array elements, not the pointers themselves.
    > However, if I add another "const" level, the error message remains the
    > same. For completeness, here again the original program:
    >
    > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};


    What you've also learned is that, despite having the keyword "const"
    somewhere in their definitions, these objects are not compile-time
    constants, so...

    > const char **z[] = {a, b};


    ....they cannot be used as initialisers. No amount of const-qualifying,
    whether of the pointers themselves or of their underlying types, can
    change that.

    Richard
    Richard Bos, Feb 10, 2004
    #12
  13. herbertF

    herbertF Guest

    Thanks for the lengthy discussion, but it seems like the question is
    still not anwered. What I've learnt from it so far is that the "const"
    seems to refer to the array elements, not the pointers themselves.
    However, if I add another "const" level, the error message remains the
    same. For completeness, here again the original program:

    int main(int argc, char *argv[]) {
    const char *a[] = {"A"};
    const char *b[] = {"B"};
    const char **z[] = {a, b};
    return (0);
    }

    and the modified one:

    int main(int argc, char *argv[]) {
    const char * const a[] = {"A"};
    const char * const b[] = {"B"};
    const char * const *z[] = {a, b};
    return (0);
    }

    The error message I'm getting is
    "t.c", line 4: error: initialization: constant expression is expected
    for variable: `z'

    Gcc with -pedantic also reports an error:
    t.c:4: initializer element is not computable at load time
    t.c:4: (near initialization for `z[0]')
    t.c:4: initializer element is not computable at load time
    t.c:4: (near initialization for `z[1]')

    Again the question: is this legal C, and if not, how can it be made
    legal?

    TiA,

    Herbert
    herbertF, Feb 10, 2004
    #13
  14. > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};
    > const char **z[] = {a, b};
    > return (0);
    > }
    >
    > and the modified one:
    >
    > int main(int argc, char *argv[]) {
    > const char * const a[] = {"A"};
    > const char * const b[] = {"B"};
    > const char * const *z[] = {a, b};
    > return (0);
    > }
    >
    > The error message I'm getting is
    > "t.c", line 4: error: initialization: constant expression is expected
    > for variable: `z'
    >
    > Gcc with -pedantic also reports an error:
    > t.c:4: initializer element is not computable at load time
    > t.c:4: (near initialization for `z[0]')
    > t.c:4: initializer element is not computable at load time
    > t.c:4: (near initialization for `z[1]')


    Okay, this is really weird. here are the 2 programs I compiled:

    (1)
    int main(int argc, char **argv) {
    const char *a[] = {"A"}; //constant pointer
    const char *b[] = {"B"};
    const char **z[] = {a, b};
    return 0;
    }

    and (2)
    int main(int argc, char **argv) {
    const char *const a[] = {"A"}; //constant pointer AND constand data
    const char *const b[] = {"B"};
    const char *const *z[] = {a,b};
    return 0;
    }
    -----

    I compiled both with GCC 3.3.2 like
    $gcc -Wall -std=c99 -pedantic const_test_1.c
    $gcc -Wall -std=c99 -pedantic const_test_2.c

    Only reply I got was:
    const_test_1.c: In function "main":
    const_test_1.c:4: warning: unused variable `z'
    (the same for the other file)

    What compiler do you have? I don't see why yours complains :/
    Chris Mantoulidis, Feb 10, 2004
    #14
  15. herbertF

    herbertF Guest

    I think I found the answer myself. Could somebody comment if my
    conclusions are correct? Here are the relevant paragraphs from the
    (draft) C99 standard:

    6.2.4 Storage duration of objects, paragraph 4:
    For such an object that does not have a variable length array type,
    storage is guaranteed to be reserved for a new instance of the object
    on each entry into the block with which it is associated; the initial
    value of the object is indeterminate. If an initialization is
    specified for the object, it is performed each time the declaration is
    reached in the execution of the block; otherwise, the value becomes
    indeterminate each time the declaration is reached. Storage for the
    object is no longer guaranteed to be reserved when execution of the
    block ends in any way. (Entering an enclosed block or calling a
    function suspends, but does not end, execution of the current block.)

    6.6, paragraph 2:

    A constant expression can be evaluated during translation rather than
    runtime, and accordingly may be used in any place that a constant may
    be.

    Paragraph 10:

    An implementation may accept other forms of constant expressions.

    6.7.8 Initialization, paragraph 1:
    Syntax
    initializer:
    assignment-expression
    { initializer-list }
    { initializer-list , }
    initializer-list:
    designationopt initializer
    initializer-list , designationopt initializer
    designation:
    designator-list =
    designator-list:
    designator
    designator-list designator
    designator:
    [ constant-expression ]
    . identifier

    The conclusion is that, because a and b are not static, their
    addresses are not known at compile or load time (and may change
    between calls to the routine in question), so they are not allowed in
    the "designator" part of an initialisation expression, which has to be
    a constant expression. Compilers who think they know enough may allow
    it (6.6, paragraph 10). To make it fully portable, the static
    qualifier has to be present for a and b (in addition to const).

    Is this correct?

    Btw., I found this about the much discussed question of where in the
    line "const" goes:

    6.7.3 Type qualifiers, paragraph 8:

    If the specification of an array type includes any type qualifiers,
    the element type is so qualified, not the array type. If the
    specification of a function type includes any type qualifiers, the
    behavior is undefined.

    H.
    herbertF, Feb 10, 2004
    #15
  16. herbertF <> wrote:
    > Thanks for the lengthy discussion, but it seems like the question is
    > still not anwered. What I've learnt from it so far is that the "const"
    > seems to refer to the array elements, not the pointers themselves.
    > However, if I add another "const" level, the error message remains the
    > same. For completeness, here again the original program:


    > int main(int argc, char *argv[]) {
    > const char *a[] = {"A"};
    > const char *b[] = {"B"};
    > const char **z[] = {a, b};
    > return (0);
    > }


    > and the modified one:


    > int main(int argc, char *argv[]) {
    > const char * const a[] = {"A"};
    > const char * const b[] = {"B"};
    > const char * const *z[] = {a, b};
    > return (0);
    > }


    > The error message I'm getting is
    > "t.c", line 4: error: initialization: constant expression is expected
    > for variable: `z'


    What you failed to learn, however, is that const-qualifying a
    variable does not make it a constant, it simply makes it
    read-only.

    Here is an example:

    const int x = 2; /* x is read-only, value is 2 */

    int array1[] = {1}; /* 1 is an integer constant, okay */
    int array2[] = {x}; /* x is not a constant, not okay! */

    Furthermore:

    x = 5; /* x is read-only, not okay! */

    Now, since the array initializer must be a constant expression,
    you are out of luck.

    --
    Alex Monjushko ()
    Alex Monjushko, Feb 10, 2004
    #16
  17. herbertF

    Chris Torek Guest

    [I snipped some gcc diagnostics from a previous poster here]

    In article <news:>
    Chris Mantoulidis <> writes:
    >Okay, this is really weird. here are the 2 programs I compiled:


    It is not all that weird, really :)

    [program 1 snipped, might as well go with the all-"const"-qualified version]
    >and (2)
    >int main(int argc, char **argv) {
    > const char *const a[] = {"A"}; //constant pointer AND constand data
    > const char *const b[] = {"B"};
    > const char *const *z[] = {a,b};
    > return 0;
    >}
    >-----
    >
    >I compiled both with GCC 3.3.2 like
    >$gcc -Wall -std=c99 -pedantic const_test_1.c
    >$gcc -Wall -std=c99 -pedantic const_test_2.c
    >
    >Only reply I got was:
    >const_test_1.c: In function "main":
    >const_test_1.c:4: warning: unused variable `z'
    >(the same for the other file)


    Try with -std=c89 instead of "-std=c99" (or, equivalently but the
    only option available in older versions of gcc, "-ansi -pedantic");
    the result should differ. Here is why.

    First, "const" in C never means "constant". Its meaning is much
    more like "read-only variable". In particular, this means that:

    static const int size = 10;
    static int a[size];

    is *always* an error, in both C89 and C99, because arrays with
    "static duration" (not quite the same thing as the "static" keyword)
    must have integer constant expressions for any specified sizes.
    (But -- while this is off-topic -- we might note that this works
    fine in C++, where "const" *does* mean "constant" whenever possible.)
    In C, a read-only variable is still a variable, and in some situations
    is even *supposed* to change -- just not by being written-on in
    the C code you are writing. For instance, the Standard specifically
    allows one to write:

    extern const volatile int tick_counter;

    and arrange for one's system to "hook up" this variable to some
    sort of constantly-running system clock (CPU clock, external timer,
    or whatever). If this tick counter "ticks" at a known speed,
    the clock() function might even be as simple as:

    /* NB: the name "tick_counter" is not in the implementor's space
    so if this were a real implementation we might want to use some
    other variable name. */
    clock_t clock(void) { return tick_counter; }

    The "const" here means that you, the programmer, cannot change it,
    but not that it is constant; and the "volatile" means that something
    outside the C code changes it, so that the compiler cannot simply
    read the variable once and then "remember" its value forever.

    (Without the "volatile", the compiler is still supposed to treat
    this as a read-only variable -- not a constant -- but *is* allowed
    to assume it never changes as well. If tick_counter is never
    explicitly initialized, it is implicitly initially zero, so a
    compiler could assume that it is *always* zero and just "return 0"
    -- not a very good clock() function.)

    With that out of the way, consider the local variables again,
    and compare against this code:

    int main(void) {
    int one = 1, two = 2;
    int a[2] = { 1, 2 }; /* works in C89 and C99 */
    int b[2] = { one, two }; /* works in C99 but not C89 */

    return 0;
    }

    Here, "one" and "two" are clearly ordinary variables -- they are not
    even "const"-qualified read-only variables. The initializers for
    "b" are thus not at all constants, but C99 accepts this, just as
    both C89 and C99 would accept:

    int three = one + two;

    The difference here is that C99 has extended the set of values
    allowed in "aggregate initializers" -- the set of values in the
    braces that initialize a[] and b[]. In C89, all aggregate initializers
    had to be constant-expressions; in C99, they may be fully-general
    expressions as long as they are initializing "automatic duration"
    variables (meaning, pretty much, "ordinary local variables").
    This means we can even write:

    int f(int zog) {
    int arr[4] = { zog, 0, 0, zog + 3 };
    ... more code ...
    }

    -- but only in C99, not in C89.

    Finally, although it is not used in the original poster's problem,
    there is one more significant change in C99 that relates back to
    "const" meaning read-only rather than constant. C99 adds a new
    type of array called a "variable length array" or VLA. Instead of
    making the array "arr" have size 4, we can now do this:

    int f(int zog) {
    int arr[zog];
    ...
    }

    This array has all the usual attributes, plus one more -- its size
    is determined at runtime. The expression:

    sizeof arr

    actually multiplies the value of "zog" by sizeof(int) at runtime.
    VLAs have some interesting pitfalls -- the draft C99 standard I
    keep handy notes that "unusual" control flow into a block (e.g.,
    via a "goto") may not be allocated properly. (More precisely,
    it says that "the behavior is undefined" if you jump into a block
    that declares a VLA, rather than sequentially executing into it.
    There are a couple of different "likely" compilation techniques
    that give somewhat different but always bizarre results having to
    do with not allocating space at the right point. These include
    losing local variables and return addresses when control flows
    back out of the block -- your code could crash in such a way that
    even a good debugger cannot figure out what happened.)

    In any case, VLAs can obscure the fact that "const" variables
    are still variables. Compare these three functions:

    int f1(int zog) { int arr[zog]; ... }
    int f2(int n) { const int zog = n; int arr[zog]; ... }
    int f3(void) { const int zog = 12; int arr[zog]; ... }

    In f1(), it is obvious that "zog" is a variable. In f2(), "zog"
    is *still* a variable, despite being "const"-qualified -- and in
    f3(), "zog" is again still a variable, despite being const-qualified
    and "obviously" always 12.

    In all three functions, "arr" is a VLA, and "sizeof arr" is supposed
    to be computed at runtime. In f3(), a C99 compiler is allowed to
    "cheat": clearly you promised that zog is always exactly 12 -- by
    making it 12 initially, promising never to change it, and not saying
    that it might be changed "by magic" ("volatile") -- so the compiler
    can replace each "zog" by 12, but only after emitting any required
    diagnostics. (In this case, there are no required diagnostics.)

    On the other hand, if we change "int arr[zog]" to "static int
    arr[zog]", or if we are using a C89 compiler, VLAs are no longer
    allowed. In this case, all three variants (f1, f2, f3) require
    diagnostics (or more precisely, a C compiler has to emit "at least
    one" diagnostic for the translation unit -- producing a single
    warning, even though there are at least three errors, suffices to
    meet the "letter of the law" as it were).

    In summary:

    - "const" never means "constant", but rather merely "read-only".

    - Variables, even if read-only, are not constant expressions
    and cannot be used where constant expressions are required.

    - If a C compiler can prove that a read-only variable is always
    some particular value, it can substitute in that value, but
    only after emitting any required diagnostic.

    - C89 requires constant expressions in quite a few more places
    than does C99, including aggregate initializers and array sizes.
    In particular, C99 removes the silly restriction in C89, where
    (as a local variable):
    int a = b;
    is OK, but:
    int a[1] = { b };
    is not; and C99 adds variable length arrays.

    Thus, if you have a C99 compiler, it may provide a better illusion
    of const-qualified variables "acting like" constants, simply because
    it allows variables in places C89 did not. But const-qualified
    variables are still not constants, and sometimes only a "#define"
    will do. (C's actual constants -- members of an "enum" type --
    only give you integral constant expressions, i.e., not floating
    point, and in practice may not be wide enough, e.g., you probably
    cannot get a "long long" constant.)
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Feb 10, 2004
    #17
    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. Alexander Farber
    Replies:
    0
    Views:
    445
    Alexander Farber
    Jun 21, 2005
  2. Replies:
    11
    Views:
    1,086
  3. Javier
    Replies:
    2
    Views:
    542
    James Kanze
    Sep 4, 2007
  4. 0m
    Replies:
    26
    Views:
    1,089
    Tim Rentsch
    Nov 10, 2008
  5. fungus
    Replies:
    13
    Views:
    871
    fungus
    Oct 31, 2008
Loading...

Share This Page