Constant Expressions in C

Discussion in 'C Programming' started by skibud2, Apr 20, 2007.

  1. skibud2

    skibud2 Guest

    Consider this example:

    u8 my_array[10];

    for (i = 0; i < (sizeof(my_array)/sizeof(u8)); i++) {
    ...
    }

    In the standard C specification, is the evaluation of
    '(sizeof(my_array)/sizeof(u8))' to 10 guarenteed to happen at compile
    time? Or is it a compiler optimization? From what I have read, it
    looks like it is a compiler optimization, but I would like to get
    confirmation.

    Now if is not guarenteed to happen at compile time, is it better to do
    something like the following:

    const u8 my_array_size = (sizeof(my_array)/sizeof(u8));

    to guarentee that you are not doing a divide a run time? On the
    systems I have worked on, divides take a very long time. However,
    almost every compiler that I have dealt with does the evaluation at
    compile time.
     
    skibud2, Apr 20, 2007
    #1
    1. Advertising

  2. On Apr 20, 11:33 pm, skibud2 <> wrote:
    > Now if is not guarenteed to happen at compile time, is it better to do
    > something like the following:
    >
    > const u8 my_array_size = (sizeof(my_array)/sizeof(u8));
    >
    > to guarentee that you are not doing a divide a run time? On the
    > systems I have worked on, divides take a very long time. However,
    > almost every compiler that I have dealt with does the evaluation at
    > compile time.


    Just curious: Which compiler didn't?
     
    christian.bau, Apr 20, 2007
    #2
    1. Advertising

  3. "skibud2" <> wrote in message
    news:...
    > Consider this example:
    >
    > u8 my_array[10];
    >
    > for (i = 0; i < (sizeof(my_array)/sizeof(u8)); i++) {
    > ...
    > }
    >
    > In the standard C specification, is the evaluation of
    > '(sizeof(my_array)/sizeof(u8))' to 10 guarenteed to happen at compile
    > time? Or is it a compiler optimization? From what I have read, it
    > looks like it is a compiler optimization, but I would like to get
    > confirmation.
    >
    > Now if is not guarenteed to happen at compile time, is it better to do
    > something like the following:
    >
    > const u8 my_array_size = (sizeof(my_array)/sizeof(u8));
    >
    > to guarentee that you are not doing a divide a run time? On the
    > systems I have worked on, divides take a very long time. However,
    > almost every compiler that I have dealt with does the evaluation at
    > compile time.
    >

    Effectively you are guaranteed that the compiler will evaluate constant
    expressions at compile time. The standard doesn't specify any particular
    sequence of machine code instructions as long as the behaviour is correct,
    because it was decided not to try impose performance requirements at all.

    --
    Free games and programming goodies.
    http://www.personal.leeds.ac.uk/~bgy1mm
     
    Malcolm McLean, Apr 21, 2007
    #3
  4. skibud2

    Ian Collins Guest

    skibud2 wrote:
    > Consider this example:
    >
    > u8 my_array[10];
    >
    > for (i = 0; i < (sizeof(my_array)/sizeof(u8)); i++) {
    > ...
    > }
    >
    > In the standard C specification, is the evaluation of
    > '(sizeof(my_array)/sizeof(u8))' to 10 guarenteed to happen at compile
    > time? Or is it a compiler optimization? From what I have read, it
    > looks like it is a compiler optimization, but I would like to get
    > confirmation.
    >

    sizeof(my_array)/sizeof(u8) is required to be a compile time constant,
    consider

    int my_array[10];
    int other[sizeof(my_array)/sizeof(int)];

    > Now if is not guarenteed to happen at compile time, is it better to do
    > something like the following:
    >
    > const u8 my_array_size = (sizeof(my_array)/sizeof(u8));
    >

    Better in the sense it makes the code easier to read.

    --
    Ian Collins.
     
    Ian Collins, Apr 21, 2007
    #4
  5. skibud2

    Jack Klein Guest

    On 20 Apr 2007 15:33:36 -0700, skibud2 <> wrote
    in comp.lang.c:

    > Consider this example:
    >
    > u8 my_array[10];
    >
    > for (i = 0; i < (sizeof(my_array)/sizeof(u8)); i++) {
    > ...
    > }
    >
    > In the standard C specification, is the evaluation of
    > '(sizeof(my_array)/sizeof(u8))' to 10 guarenteed to happen at compile
    > time? Or is it a compiler optimization? From what I have read, it
    > looks like it is a compiler optimization, but I would like to get
    > confirmation.
    >
    > Now if is not guarenteed to happen at compile time, is it better to do
    > something like the following:
    >
    > const u8 my_array_size = (sizeof(my_array)/sizeof(u8));


    I wouldn't do this, C is not C++. If you define this at file scope,
    it has external linkage and the compiler must actually create the
    object, because it cannot tell whether another translation unit will
    refer to it by name.

    Even if you define it as static, some C compilers will create the
    object and read its value when you use it in an expression.

    > to guarentee that you are not doing a divide a run time? On the
    > systems I have worked on, divides take a very long time. However,
    > almost every compiler that I have dealt with does the evaluation at
    > compile time.


    Despite what others have said, the C language standard does not
    require a compiler to evaluate constant expressions at compile time
    unless it needs to use the value at compile time, as in Ian's example
    of using it to define the size of an array.

    Another such case would be where an integer constant is used as a case
    value in a switch statement.

    In this particular case, it makes much more sense to define the value
    ahead of time and use it both for defining the array and when you need
    the number of its elements:

    #define MY_ARRAY_SIZE /* some value */

    u8 my_array [MY_ARRAY_SIZE];

    In the general case, you are better off using a nameless enum, so long
    as the value fits in the range of an int:

    enum { my_array_size = sizeof my_array / sizeof *my_array };

    This will be evaluated at compile time and not create an object at run
    time.

    Also note that in general, the expression for the number of elements
    should make use of the explicit conversion of an array name to a
    pointer, and using that to access the type of the members:

    elements = sizeof array_name / sizeof *array_name;

    If you ever decide that you need to change the type, say to int or
    long, you don't have to hunt down and make sure you change all the
    sizeof expressions.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Apr 21, 2007
    #5
  6. skibud2

    Ian Collins Guest

    Jack Klein wrote:
    >
    > Despite what others have said, the C language standard does not
    > require a compiler to evaluate constant expressions at compile time
    > unless it needs to use the value at compile time, as in Ian's example
    > of using it to define the size of an array.
    >

    Thanks for the clarification Jack, I wasn't aware of that "unless".

    --
    Ian Collins.
     
    Ian Collins, Apr 21, 2007
    #6
  7. skibud2

    pete Guest

    skibud2 wrote:
    >
    > Consider this example:
    >
    > u8 my_array[10];
    >
    > for (i = 0; i < (sizeof(my_array)/sizeof(u8)); i++) {
    > ...
    > }
    >
    > In the standard C specification, is the evaluation of
    > '(sizeof(my_array)/sizeof(u8))' to 10 guarenteed to happen at compile
    > time? Or is it a compiler optimization? From what I have read, it
    > looks like it is a compiler optimization, but I would like to get
    > confirmation.
    >
    > Now if is not guarenteed to happen at compile time, is it better to do
    > something like the following:
    >
    > const u8 my_array_size = (sizeof(my_array)/sizeof(u8));
    >
    > to guarentee that you are not doing a divide a run time? On the
    > systems I have worked on, divides take a very long time. However,
    > almost every compiler that I have dealt with does the evaluation at
    > compile time.


    You currently engaged in premature microoptimization.
    The compiler may evaluate the constant expression
    either at compile time or during run time.
    Constant expressions of integer type
    are commonly evaluated at compile time.
    Either of the two ways of coding that you've shown
    could be slower or faster.

    If (sizeof array / sizeof array[0]) is evaluated at compile time,
    then there's a chance that comparing
    i < compile_time_constant
    might be faster than
    i < run_time_variable

    --
    pete
     
    pete, Apr 21, 2007
    #7
  8. On Apr 21, 11:37 am, pete <> wrote:
    > If (sizeof array / sizeof array[0]) is evaluated at compile time,
    > then there's a chance that comparing
    > i < compile_time_constant
    > might be faster than
    > i < run_time_variable


    On the other hand, a constant might also be slower than a runtime
    variable. (And I do have real examples for this, where a construct
    like

    static int s_one = 1;
    int one = s_one;

    and using "one" instead of "1" with a particular compiler led to
    significantly faster code. )
     
    christian.bau, Apr 21, 2007
    #8
  9. skibud2

    Guest

    On Apr 21, 9:35 am, "christian.bau" <>
    wrote:
    > On Apr 21, 11:37 am, pete <> wrote:
    >
    > > If (sizeof array / sizeof array[0]) is evaluated at compile time,
    > > then there's a chance that comparing
    > > i < compile_time_constant
    > > might be faster than
    > > i < run_time_variable

    >
    > On the other hand, a constant might also be slower than a runtime
    > variable. (And I do have real examples for this, where a construct
    > like
    >
    > static int s_one = 1;
    > int one = s_one;
    >
    > and using "one" instead of "1" with a particular compiler led to
    > significantly faster code. )


    <OT>

    That really surprises me. And 'significantly' faster? that's puzzling.
    Mostly small integer constants (that can fit in, say 16 bits) are
    directly
    encoded in the same machine instruction. Thus no load/store for the
    operand.
    So I'm wondering why any compiler would ever do things slowly on using
    a literal '1'
    than using thru' a variable (named like one above).

    </OT>

    Karthik
     
    , Apr 21, 2007
    #9
  10. "" <> writes:
    > On Apr 21, 9:35 am, "christian.bau" <>
    > wrote:
    >> On Apr 21, 11:37 am, pete <> wrote:
    >> > If (sizeof array / sizeof array[0]) is evaluated at compile time,
    >> > then there's a chance that comparing
    >> > i < compile_time_constant
    >> > might be faster than
    >> > i < run_time_variable

    >>
    >> On the other hand, a constant might also be slower than a runtime
    >> variable. (And I do have real examples for this, where a construct
    >> like
    >>
    >> static int s_one = 1;
    >> int one = s_one;
    >>
    >> and using "one" instead of "1" with a particular compiler led to
    >> significantly faster code. )

    >
    > <OT>
    > That really surprises me. And 'significantly' faster? that's puzzling.
    > Mostly small integer constants (that can fit in, say 16 bits) are
    > directly
    > encoded in the same machine instruction. Thus no load/store for the
    > operand.
    > So I'm wondering why any compiler would ever do things slowly on using
    > a literal '1'
    > than using thru' a variable (named like one above).


    Machine instructions still have to be loaded from memory; "one" could
    have been stored in a register. (That's pure speculation, off the top
    of my head.)

    > </OT>


    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Apr 22, 2007
    #10
  11. On Apr 21, 11:38 pm, "" <> wrote:

    > That really surprises me. And 'significantly' faster? that's puzzling.
    > Mostly small integer constants (that can fit in, say 16 bits) are
    > directly
    > encoded in the same machine instruction. Thus no load/store for the
    > operand.
    > So I'm wondering why any compiler would ever do things slowly on using
    > a literal '1'
    > than using thru' a variable (named like one above).


    The PowerPC has a single instruction that performs that operation a =
    b << c; if a, b and c are all in registers. There is _no_ single
    instruction to calculate a = 1 << c: Two instructions are needed, one
    to load the constant 1 into a register, and one to shift. Now if you
    have an operation that calculates 1 << n in the critical path of a
    very short loop with gazillions of iterations then this can make a
    significant difference. This happened to me on a compiler that was
    actually quite good at optimisations, except that it didn't recognise
    that a constant can actually be a loop-invariant that should be
    removed from a loop!

    Similar things can happen with floating-point constants used in a
    loop; a compiler should hold them in a register but often doesn't
    whereas complex operations could be removed as loop-invariants from a
    loop, with the result being kept in a register.
     
    christian.bau, Apr 23, 2007
    #11
  12. Ian Collins <> wrote:
    > Jack Klein wrote:
    > > Despite what others have said, the C language standard does not
    > > require a compiler to evaluate constant expressions at compile time


    Vacuously true.

    > > unless it needs to use the value at compile time, as in Ian's example
    > > of using it to define the size of an array.

    >
    > Thanks for the clarification Jack, I wasn't aware of that "unless".


    What "unless"?

    The standard simply says (Epmhasis mine): "A constant expression _can_
    be evaluated during _translation_ rather than runtime..." There is no
    "must"
    or "shall" precluding runtime evaluation of all constant expressions.

    Expectations of QoI is the only guide. But when it comes to constant
    expressions, expectations are pretty high these days. :)

    --
    Peter
     
    Peter Nilsson, Apr 23, 2007
    #12
  13. skibud2

    Ian Collins Guest

    Peter Nilsson wrote:
    > Ian Collins <> wrote:
    >
    >>Jack Klein wrote:
    >>
    >>>Despite what others have said, the C language standard does not
    >>>require a compiler to evaluate constant expressions at compile time

    >
    > Vacuously true.
    >

    Vacuous?

    >>>unless it needs to use the value at compile time, as in Ian's example
    >>>of using it to define the size of an array.

    >>
    >>Thanks for the clarification Jack, I wasn't aware of that "unless".

    >
    > What "unless"?
    >
    > The standard simply says (Epmhasis mine): "A constant expression _can_
    > be evaluated during _translation_ rather than runtime..." There is no
    > "must"
    > or "shall" precluding runtime evaluation of all constant expressions.
    >
    > Expectations of QoI is the only guide. But when it comes to constant
    > expressions, expectations are pretty high these days. :)
    >

    I have never come across a compiler that does not do this, so naturally
    I assumed it was standard behaviour.

    > --
    > Peter
    >

    Your sig is missing the space after the --

    --
    Ian Collins.
     
    Ian Collins, Apr 23, 2007
    #13
  14. Ian Collins <> wrote:
    > Peter Nilsson wrote:
    > > Ian Collins <> wrote:
    > > > Jack Klein wrote:
    > > > > Despite what others have said, the C language standard does not
    > > > > require a compiler to evaluate constant expressions at compile time

    > >
    > > Vacuously true.

    >
    > Vacuous?


    Yes, the notion of compile and link time are not mentioned. The word
    "compiler"
    only appears in a non-normative footnote of N1124. Obviously there is
    an intuitive
    mapping between the translation phases...

    Preprocessing - TP1..4
    Compilation - TP5..7
    Linking - TP8

    That said, there is often a degree of overlap on actual
    implementations,
    particularly between compilation and preprocessing, especially with
    pragma
    extensions.

    > > > > unless it needs to use the value at compile time, as in Ian's example
    > > > > of using it to define the size of an array.
    > > >
    > > > Thanks for the clarification Jack, I wasn't aware of that "unless".

    > >
    > > What "unless"?
    > >
    > > The standard simply says (Epmhasis mine): "A constant expression _can_
    > > be evaluated during _translation_ rather than runtime..." There is no
    > > "must" or "shall" precluding runtime evaluation of all constant expressions.
    > >
    > > Expectations of QoI is the only guide. But when it comes to constant
    > > expressions, expectations are pretty high these days. :)

    >
    > I have never come across a compiler that does not do this,


    Nor are you likely to. Conditional preprocessing often involves
    constant
    expressions, so you're unlikely to find an implementation that can't
    work
    them out as it goes.

    > so naturally I assumed it was standard behaviour.


    Whilst highly pragmatic and practical in nature, the language standard
    is nonetheless an abstraction.

    > > --
    > > Peter

    >
    > Your sig is missing the space after the --


    As is...

    > --
    > Ian Collins.


    Of course, I believe that you typed/inserted it.

    Either google or IE managed to delete it. AFAIK, I'm not in a position
    to
    rectify this. If you're going to tell me how annoying it is for you,
    then
    realise that as a very reluctant google groups user I probably have to
    do
    things ten times more annoying than manually trimming signatures.

    --
    Peter
     
    Peter Nilsson, Apr 23, 2007
    #14
  15. skibud2

    Ian Collins Guest

    Peter Nilsson wrote:
    > Of course, I believe that you typed/inserted it.
    >
    > Either google or IE managed to delete it. AFAIK, I'm not in a position
    > to
    > rectify this. If you're going to tell me how annoying it is for you,
    > then
    > realise that as a very reluctant google groups user I probably have to
    > do
    > things ten times more annoying than manually trimming signatures.
    >

    Like reading badly wrapped lines :)

    --
    Ian Collins.
     
    Ian Collins, Apr 23, 2007
    #15
  16. On 22 Apr 2007 17:16:57 -0700, Peter Nilsson <>
    wrote:

    > Ian Collins <> wrote:
    > > Jack Klein wrote:
    > > > Despite what others have said, the C language standard does not
    > > > require a compiler to evaluate constant expressions at compile time

    >
    > Vacuously true.
    >
    > > > unless it needs to use the value at compile time, as in Ian's example
    > > > of using it to define the size of an array.

    > >
    > > Thanks for the clarification Jack, I wasn't aware of that "unless".

    >
    > What "unless"?
    >
    > The standard simply says (Epmhasis mine): "A constant expression _can_
    > be evaluated during _translation_ rather than runtime..." There is no
    > "must"
    > or "shall" precluding runtime evaluation of all constant expressions.
    >
    > Expectations of QoI is the only guide. But when it comes to constant
    > expressions, expectations are pretty high these days. :)


    True. But for some _integer_ constant expressions:

    - the ICE specifying bitfield width in a struct must not be greater
    than the 'normal' width (before C99, of int) nor less than zero and
    if zero must not be named; this is a constraint and so any violation
    of it must be diagnosed. It's hard to do that without evaluating the
    constant expression at compile time, unless you weasel out with a
    blanket diagnostic like "this program may contain errors".

    - the ICE specifying the value of an enumeratee must be in range of
    int, as a constraint. This might not be too hard to defer, except that
    the enumeratee can in turn be used in other ICEs which may need to be
    evaluated.

    - if the (integer) expression for array bound in a declarator is
    constant it must be positive as a constraint; plus whether two array
    types are compatible depends on whether their bounds are ICEs with the
    same value, and compatibility is in some constraints.

    - (ICEs for) case labels in a switch must be distinct, a constraint.

    And as already noted, (integer) constant expressions in #if or #elif
    must be evaluated at preprocessing time, at least in principle BEFORE
    compile time, because
    #if 0
    #include "nonexistentfile"
    #endif
    int main (void) { return 0; }
    must succeed (or at least not fail because of that construct).

    OTOH it may actually make sense to defer floating-point constant
    expressions in cases of cross compilation where the target floating
    point arithmetic is different from the host and not worth the trouble
    of simulating or (God forbid) not documented well enough to simulate.

    - formerly david.thompson1 || achar(64) || worldnet.att.net
     
    David Thompson, May 21, 2007
    #16
    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. Christopher M. Lusardi
    Replies:
    1
    Views:
    4,132
  2. Martin Magnusson
    Replies:
    2
    Views:
    534
    John Harrison
    Oct 8, 2004
  3. Tor Erik Soenvisen
    Replies:
    14
    Views:
    591
    Tim Roberts
    Nov 23, 2006
  4. Replies:
    4
    Views:
    357
    Keith Thompson
    Dec 14, 2006
  5. Replies:
    13
    Views:
    13,027
    Kai-Uwe Bux
    Jan 22, 2007
Loading...

Share This Page