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)