1

Can a reasonable decent compiler discard this const static variable

class A{
     const static int a = 3;
}

if it is nowhere used in the compiled binary or does it show up anyway in the binary?

Gabriel
  • 8,990
  • 6
  • 57
  • 101
  • I believe that you can actually check this by experimenting. Unless you are asking whether it's *allowed to* by the standard, but then this is missing [tag:language-lawyer]. – Griwes Oct 08 '15 at 08:19
  • How would you tell if it was optimized out? What difference does it make to the program? – Barmar Oct 08 '15 at 08:23
  • @Barmar: You can look at a assembly language listing file generated by the compiler for a release build. – User5910 Apr 21 '17 at 23:57
  • @User5910 I meant how could you tell from the behavior of the program? – Barmar Apr 22 '17 at 00:19
  • An ideal optimizer will make the program faster and/or smaller (depending on optimizations selected) without changing the output. If you want to code up an example to see for yourself you may have to run it a million times to accumulate a measurable amount of runtime difference. It's the difference between encoding the constant into an instruction instead of loading the value from memory elsewhere. The biggest potential win is probably when that constant's memory is swapped out and would take extra long to load from disk. – User5910 Apr 23 '17 at 01:33

2 Answers2

5

Short answer: Maybe. The standard does not say the compiler HAS to keep the constants (or strings, or functions, or anything else), if it's never used.

Long answer: It very much depends on the circumstances. If the compiler can clearly determine that it is not used, it will remove unused constants. If it can't make that determination, it can not remove the unused constant, since the constant COULD be used by something that isn't currently known by the compiler (e.g. another source file).

For example, if class A is inside a function, the compiler can know this class is not used elsewhere, and if the constant isn't used in the function, then it's not used anywhere. If the class is in a "global" space, such that it could be used somewhere else, then it will need to keep the constant.

This gets even more interesting with "whole program optimization" or "link time optimization" (both from now on called LTO), where all the code is actually optimized as one large lump, and of course, "used" or "not used" can be determined for all possible uses.

As you can imagine, the result will also depend on how clever the compiler (and linker for the LTO) is. All compilers should follow the principle of "if in doubt keep it".

You can of course experiment, and write some code where you use the variable, and then remove the use, and see what difference it makes to the assembly code (e.g. g++ -S x.cpp or clang++ -S x.cpp, and look at the resulting x.s file).

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
1

When optimizations are disabled, the answer is compiler-dependent. But when optimizations are enabled, the end result is the same irrespective of the compiler. Let's assume that optimizations are enabled.

The compiler will not emit a definition for a const static field in the generated object file when both of the following conditions holds:

  1. It can resolve all uses of the field with the constant value it was initialized to.
  2. There is at most one source code file that has used the field (there is an exception which I'll discuss at the end).

I'll discuss the second condition later. But now let's focus on the first. Let's see an example. Suppose that the target platform is 32-bit and that we have defined the following type:

// In MyClassA.h
class MyClassA{
public:
     const static int MyClassAField;
};

// In MyClassA.cpp (or in MyClassA.h if it was included in at most one cpp file)
const int MyClassA::MyClassAField = 2;

Most compilers consider int to be a 32-bit signed integer. Therefore, on a 32-bit processor, most instructions can handle a 32-bit constant. In this case, the compiler will be able to replace any uses of MyClassAField with the constant 2 and that field will not exist in the object file.

On the other hand, if the field was of type double, on a 32-bit platform, instructions cannot handle 64-bit values. In this case, most compilers emit the field in the object file and uses SSE instructions and registers to 64-bit value from memory and process them.

Now I'll explain the second condition. If there is more than one source code file that is using the field, it cannot be eliminated (irrespective of whether Whole Program Optimization (WPO) is enabled or not) because some object file has to include the definition of the field so that the linker can use it for other object files. However, the linker, if you specified the right switch, can eliminate the field from the generated binary.

This is a linker optimization enabled with /OPT:REF for VC++ and --gc-sections for gcc. For icc, the names of the switches are the same (/OPT:REF on Windows and --gc-sections on Linx and OSX). However, the compiler has to emit every function and static or global field in a separate section in the object file so that the linker can eliminate it.

There is a catch, however. If the field has been defined inline as follows:

class MyClassA{
public:
     const static int MyClassAField = 2;
};

Then the compiler itself will eliminate the definition of this field from every object file that uses it. That's because every source code file that uses it includes a separate definition. Each of them is compiled separately, the compiler itself will optimize the field away using an optimization called constant propagation. In fact, the VC++ compiler perform this optimization even if optimizations are disabled.

When optimizations are disabled, whether a const static field will be eliminated or not depends on the compiler, but probably it will not be eliminated.

Hadi Brais
  • 22,259
  • 3
  • 54
  • 95