2

Assume the following code:

static int array[10];

int main ()
{
    for (int i = 0; i < (sizeof(array) / sizeof(array[0])); i++)
    {
        // ...
    }
}

The result of sizeof(array) / sizeof(array[0]) should in theory be known at compile time and set to some value depending on the size of the int. Even though, will the compiler do the manual division in run time each time the for loop iterates?

To avoid that, does the code need to be adjusted as:

static int array[10];

int main ()
{
    static const int size = sizeof(array) / sizeof(array[0]);
    for (int i = 0; i < size; i++)
    {
        // ...
    }
}
Łukasz Przeniosło
  • 2,725
  • 5
  • 38
  • 74
  • 5
    A compiler is free to leave it to the program to do in run time but I'm not sure if any compiler is actually doing that. It would surprise me. Any optimizing compiler worth the name _should_ do this division at compile time. Unrelated: Make it `sizeof array / sizeof *array`. You are not taking the `sizeof` a _type_. You take if from an _expression_. – Ted Lyngmo Nov 25 '21 at 17:32
  • 2
    The best way to check for *your* compiler is build the code (with optimizations enabled) and then check the generated assembly code. – Some programmer dude Nov 25 '21 at 17:35
  • 1
    *As long as optimizations are enabled*, mainstream compilers (GCC, Clang, VS and ICC) optimize the division and replace it with a constant. Even if a compiler does not, it will certainly replace the division with a shift because the item size is typically a power of two (and even it is not, compilers can use some tricks). – Jérôme Richard Nov 25 '21 at 17:39
  • 2
    A compiler is required to have the ability to evaluate constant expressions at compile time because constant expressions are required in certain contexts, but the compiler is free to evaluate constant expressions at run-time outside of those certain contexts if it wants to (but why would it)? – Ian Abbott Nov 25 '21 at 17:41
  • 5
    Hint: if you want to check quickly for your compiler, try Matt Godbolt's [Compiler Explorer](https://godbolt.org/z/1n6EdboaY). You can see none of the MSVC, GCC or CLANG versions I chose have any kind of DIV or shift instructions. – Useless Nov 25 '21 at 17:42
  • 1
    Re your tags, this doesn't have anything to do with the preprocessor. The preprocessor doesn't know about types and so `sizeof` is not evaluated during that pass. – Nate Eldredge Nov 25 '21 at 21:10
  • It's easier for even the most primitive conformant compilers to just fold integer constant expressions rather than generate runtime instructions for those expressions. Of course, a compiler is free to be proactively pessimizing, but then it could well be conjuring up useless instructions all over the place regardless of what you feed it. – Petr Skocik Nov 26 '21 at 08:16

2 Answers2

1

Even though, will the compiler do the manual division in run time each time the for loop iterates?

No. It's an integer constant expression which will be calculated at compile-time. Which is why you can even do this:

int some_other_array [sizeof(array) / sizeof(array[0])];

To avoid that, does the code need to be adjusted as

No.

See for yourself: https://godbolt.org/z/rqv15vW6a. Both versions produced 100% identical machine code, each one containing a mov ebx, 10 instruction with the pre-calculated value.

Lundin
  • 195,001
  • 40
  • 254
  • 396
0

You should write the code in whatever way is most readable and maintainable for you. (I'm not making any claims about which one that is: it's up to you.) The two versions of the code you wrote are so similar that a good optimizing compiler should probably produce equally good code for each version.

You can click on this link to see what assembly your two different proposed codes generate in various compilers:

https://godbolt.org/z/v914qYY8E

With GCC 11.2 (targetting x86_64) and with minimal optimizations turned on (-O1), both versions of your main function have the exact same assembly code. With optimizations turned off (-O0), the assembly is slightly different but the size calculation is still done at a compile time for both.

Even if you doubt what I am saying, it is still better to use the more readable version as a starting point. Only change it to the less readable version if you find an actual example of a programming environment where doing that would provide a meaningful speed increase for you application. Avoid wasting time with premature optimization.

David Grayson
  • 84,103
  • 24
  • 152
  • 189