3

Many times, reading around, I found definitions like this one:

Definitions are not executable statements. They’re messages to the compiler. For example, the definition int i; simply tells the compiler the type of variable i and instructs the compiler to reserve space in memory for the variable.

Statements like this one leave me always confused, because, IMHO, everything can be seem as "requiring an action". For example, in this case, the computer has to perform some actions to allocate some memory.

So what are those statements really referring to?

zer0uno
  • 7,521
  • 13
  • 57
  • 86
  • Which hood do you have in mind? – Kerrek SB Feb 05 '17 at 17:01
  • 1
    Memory allocation isn't normally bound to a single statement. A typical C compiler will allocate memory for all local variables at once, at function entry, no matter how many variable declarations you have or how they're spread over the function. Or maybe `i` gets placed in a register and no memory is allocated for it. – melpomene Feb 05 '17 at 17:05
  • 1
    When talking about "executable statements", the actions in question are those performed when the program runs. Ones done by the compiler "don't count". – John Hascall Feb 05 '17 at 17:05
  • This might answer your question: http://stackoverflow.com/questions/30199744/cost-of-static-memory-allocation-vs-dynamic-memory-allocation-in-c/41662037 The only difference is you're basically only asking about static and automatic allocations without dynamic ones. – Petr Skocik Feb 05 '17 at 17:06
  • An variable declaration with an initial value is an interesting hybrid. `int i;` not executable / `int i = 0;` hmmm / `int i = complexFunction(a1, a2);` seems pretty executable... – John Hascall Feb 05 '17 at 17:13
  • C has external definitions and local definitions. What kind of definitions is that quote referring to? External definitions are definitely not statements, since they are located outside of control flow. Local definitions are a different story: they are "statements" in a sense, since they can involve initialization. But in C language declarations are not officially recognized as statements. – AnT stands with Russia Feb 05 '17 at 17:15
  • @JohnHascall is memory allocation made by the compiler? I mean, are you saying that when I launch my program (`./a.out`) the compiler is still in action? o_O – zer0uno Feb 05 '17 at 17:26
  • 1
    The statement is in indeed not correct: the compiler does not allocate space. It will emit directives into the object file that will reserve space once the executable is loaded into memory for execution. – Paul Ogilvie Feb 05 '17 at 17:58
  • The compiler allocates memory for static variables (typically in a data "section" of the a.out image) and automatic variables (typically by assigning them space on the stack). Of course, there is also memory allocated when the program runs (eg by sbrk/map/malloc and friends and also by the loader if there are dynamic libs, etc) – John Hascall Feb 05 '17 at 21:15
  • @JohnHascall I do not agree. If the compiler allocated memory then it would mean That even if I do not run the program some memory is allocated uselessly. – zer0uno Feb 05 '17 at 21:53
  • Perhaps we are just arguing over the word "allocated". If you, on a UNIXy box do the command `size a.out` (or on any program) you will see the sizes of the data segment, so those are variables "allocated" in the object file, but they will also be "allocated" in memory by the loader when the program runs. – John Hascall Feb 05 '17 at 22:02

5 Answers5

4

C language recognizes the similarity between local declarations and statements. This is reflected in

6.8 Statements and blocks

3 A block allows a set of declarations and statements to be grouped into one syntactic unit. The initializers of objects that have automatic storage duration, and the variable length array declarators of ordinary identifiers with block scope, are evaluated and the values are stored in the objects (including storing an indeterminate value in objects without an initializer) each time the declaration is reached in the order of execution, as if it were a statement, and within each declaration in the order that declarators appear.

However, formally, declarations are not classified as statements in C.

Note that "statement-ish" properties of a local declarations are actually tied to initialization. As for memory allocation... the language does not actually specify when exactly that memory allocation occurs. It does not necessarily occur when control passes over the definition.

External definitions are definitely not statements since they are not involved in the control flow.

Community
  • 1
  • 1
AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I think this says that initializers are executed at the moment they are encountered. Initializers that would call functions or have side-effects will thus be execued in proper order of the execution path. – Paul Ogilvie Feb 05 '17 at 17:54
1

Imagine getting a new car from a car dealer. They will show you where the switches for the headlights are, how the gears are arranged and how to open the trunk. This is all declarative. Nothing is actually happening. In terms of a compiler: no output will be created.

Once you start using the car, you will perform different actions according to the knowledge you've been given. You will shift gears accordingly and use the proper switch to turn on the headlights. In terms fo a compiler: the compiled output will vary depending on the declarations given beforehand.

Hazzit
  • 6,782
  • 1
  • 27
  • 46
1

Compilers translate the C language into machine code, which can be executed by the CPU. It's often easy to see which bytes of machine code correspond to which statements in your C code. Debuggers use this correspondence when showing how your C code runs.

So the meaning of "a declaration is not an executable statement" is that no machine code corresponds to a declaration. This also means that:

  • CPU doesn't spend any time to "run" the declaration (but the compiler does spend time to examine it)
  • A visual debugger will "skip" the declaration when running your program step by step

You can see this in the online compiler explorer, which does this for C++, but it's close enough to C. It paints each line of code in a different colour to visualize which lines generate which machine code. An example from there:

Input C/C++ code

int square(int num)             // painted in white
{                               // painted in teal
    int result;                 // painted in white
    result = num * num;         // painted in yellow
    return result;              // painted in gray
}                               // painted in red

Output assembly code (represents machine code)

square(int):
        push    rbp                          // painted in green
        mov     rbp, rsp                     // painted in green
        mov     DWORD PTR [rbp-20], edi      // painted in green
        mov     eax, DWORD PTR [rbp-20]      // painted in yellow
        imul    eax, DWORD PTR [rbp-20]      // painted in yellow
        mov     DWORD PTR [rbp-4], eax       // painted in yellow
        mov     eax, DWORD PTR [rbp-4]       // painted in gray
        pop     rbp                          // painted in red
        ret                                  // painted in red

You can see that lines painted in white (declarations) "don't generate code", and "are not executable statements".


The "not executable" idea is not a hard rule; just a guideline. Some situations where a declaration is "executable":

int x = 0; // a trivial calculation, but it will appear in machine code
int y = x * (x + 1); // a non-trivial calculation
int a[rand() % 10 + 1]; // possible without initialization too (suggested by by user AnT)
anatolyg
  • 26,506
  • 9
  • 60
  • 134
  • That's actually inaccurate in general case. Firstly, in C I can declare `int a[rand() % 10 + 1];` and this declaration will definitiely generate machine code (not even mentioning declarations with initalizers). Secondly, in your example it is too easy to optimize away local variables. In more involved examples the function prologue code would indeed allocate memory for all local variables by moving the stack pointer. The "compiler explorer" would not be able to show the matching between the lines, of course, but memory allocation would still be there. – AnT stands with Russia Feb 05 '17 at 18:23
  • 1
    The part about *declarations* vs. *defintions* is completely incorrect. The `int result` in your first example is a *definition*. Defintion does not require an initializer to become a defintion, contrary to what you seem to believe. – AnT stands with Russia Feb 05 '17 at 18:26
0

In the impreative programming paradigm, a statement is a description of what and how the program should take an action, while a declaration is a description of what the tools the program should use. The line int i only declares that the program requires an object of type (int), and the line int i = 0 declares that the program requires an object of type (int) with an initial value of zero. None of those are statements, even both could require action from the program.

You are right that every line of code could potentially(1) involve some "execution" from the program. But the distinction is about what the language is, as a description of algorithms, not how it is implemented in real-world machines.

(1): any declaration or statement can be optimized-out, for instance

giusti
  • 3,156
  • 3
  • 29
  • 44
  • technically, `int i = 0` is a declaration *and* an initialization statement. – Hazzit Feb 05 '17 at 17:11
  • But that's not necessarily a statement in the imperative paradigm sense. It is up to the compiler to determine how room for that object is allocated and initialized. For instance, if you have that definition in file scope, most compilers will transform that into a data segment in the code, so no action *from the program* will be required to initialize `i`. – giusti Feb 05 '17 at 17:26
  • "not necissarily" is the key here. in a local function, the same initialization *would* create code. Same with `int i = foo()`. So I'd like to rephrase my sentence: `int i = 0` is a declaration *and possibly* an initialization statement. – Hazzit Feb 05 '17 at 17:37
0

int i; in the global context or static int i; anywhere reserve space for i and zero-initialize it. These allocations are typically glued with other allocations and done in one fell swoop when the program is loaded.

int i inside a function does potentially nothing if you don't use the variable. If you do use it, the compiler will try to use it as an alias for a CPU register. If all registers are taken and an old register variable cannot be reused or if you take the address of the variable, the compiler will need to spill the variable into the stack. All the stack variables of a function will typically be allocated upon entering the function, all at once, and the allocation will be done by incrementing (/decrementing) the stack pointer (in a register, hidden from you when you're in C). In essence, the CPU-time cost of allocating an automatic variable will be at most a fraction of the time it takes to subtract an integer.

Petr Skocik
  • 58,047
  • 6
  • 95
  • 142