I can build my own .sln manually on my machine, or have Azure DevOps build it on a remote machine. The software is targeting .NET Core 3.1, and using C 17. I had noticed that building the same code, from the same branch, produced a different size .exe: the remote one had 9 KB less than the local one.
I finally got the same result when I upgraded the remote machine's version of Visual Studio 2019 to match mine (from 16.8.something up to 16.11.14). But how can this difference be explained? Is there something missing from the smaller file? It should have all the same methods, logic, and functionality. There were no errors, so no part of it could have failed to compile.
I also have to build Java projects with Maven and have heard that it can be built "slightly differently" depending on Maven versions. That made sense at first, but in hindsight I don't know exactly what that means.
Has anyone been really in the weeds with software builds (specifically with Visual Studio and its C compiler) that can explain this concept of "slightly different builds", or has a good idea?
Would both version be functionally identical, or is there no easy way to tell?
CodePudding user response:
The C standard does not dictate the machine code that should be produced by the compiler. It just specifies the expected observable behavior.
So if for example you have a for
loop the standard dictates the behavior (initializing, checking the condition etc.). But you can translate to machine code in various ways, e.g. using different registers, or executing the statements in different order (as long as the observable behavior is the same).
This principle is called the as-if rule.
So different compilers (or compiler versions) can produce different machine code. The cause might be either different optimizations, or different ways of translating C into machine code (as the mapping between C and machine code is not 1-1).
Examples related to optimizations: if you have various statements in the code that are not dependent (e.g. you modify different unrelated variable), the compiler/optimizer might re-order them if memory access patern would be more efficient. Or the compiler/optimizer might eliminate statement that do not have observable behavior (like incrementing a variable that is never read afterwards). Another example is whether functions are inlined which is entirly up to the compiler/optimizer, and affect the binary code.
Therefore there's no guarentee for the size (or content) of a compiled binary file.