Memory location for local C variables

P

Pete

Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code? I have been
experimenting with how gcc converts C code to machine code and have
found that no matter how I define a function's local variables, they
are always stored in the same order on the stack.

For example, whether I define a the function like this:

int test_function() {
int flag = 0;
char buffer[20];
...
}

or like this:

int test_function() {
char buffer[20];
int flag = 0;
...
}

I have found that buffer will always be placed on the stack after the
flag (that is buffer's memory address will be lower than flag's)... at
least on a machine running FreeBSD 7.

Any advise would be greatly appreciated since I have been unable to
find any answers by reading the manpages and various articles on
google.
 
I

Ian Collins

Pete said:
Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code? I have been
experimenting with how gcc converts C code to machine code and have
found that no matter how I define a function's local variables, they
are always stored in the same order on the stack.
Well a gcc group would be the place to ask.
For example, whether I define a the function like this:

int test_function() {
int flag = 0;
char buffer[20];
...
}

or like this:

int test_function() {
char buffer[20];
int flag = 0;
...
}

I have found that buffer will always be placed on the stack after the
flag (that is buffer's memory address will be lower than flag's)... at
least on a machine running FreeBSD 7.
Why do you care?
 
B

Bart

Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code? I have been
experimenting with how gcc converts C code to machine code and have
found that no matter how I define a function's local variables, they
are always stored in the same order on the stack.

It sounds a bit dangerous relying on variables being in a particular
order.

There could be any number of reasons for the choice of the compiler,
for example they might simply be in alphabetical order.

For more control you can try enclosing the variables in a struct.
 
P

Pete

Pete said:
Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code? I have been
experimenting with how gcc converts C code to machine code and have
found that no matter how I define a function's local variables, they
are always stored in the same order on the stack.

Well a gcc group would be the place to ask.


For example, whether I define a the function like this:
int test_function() {
int flag = 0;
char buffer[20];
...
}
or like this:
int test_function() {
char buffer[20];
int flag = 0;
...
}
I have found that buffer will always be placed on the stack after the
flag (that is buffer's memory address will be lower than flag's)... at
least on a machine running FreeBSD 7.

Why do you care?

Asking a gcc group was my second choice... and I dont REALLY care that
much. I was "working through" some examples in a C/assembly tutorial I
found online and it mentioned that by changing the order they were
defined in the source, you can change the order on the stack. It
wasn't really important, but since it didn't work it "perked" my
curiosity.

Thanks for the response.
 
K

Keith Thompson

Pete said:
Pete said:
Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code? I have been
experimenting with how gcc converts C code to machine code and have
found that no matter how I define a function's local variables, they
are always stored in the same order on the stack.

Well a gcc group would be the place to ask.
For example, whether I define a the function like this:
int test_function() {
int flag = 0;
char buffer[20];
...
}
or like this:
int test_function() {
char buffer[20];
int flag = 0;
...
}
I have found that buffer will always be placed on the stack after the
flag (that is buffer's memory address will be lower than flag's)... at
least on a machine running FreeBSD 7.

Why do you care?

Asking a gcc group was my second choice... and I dont REALLY care that
much. I was "working through" some examples in a C/assembly tutorial I
found online and it mentioned that by changing the order they were
defined in the source, you can change the order on the stack. It
wasn't really important, but since it didn't work it "perked" my
curiosity.

Curiosity is good, but you need to find a better tutorial (unless it's
intended to describe one particular implementation. The C language
doesn't even guarantee the existence of a "stack" in the sense you're
probably thinking of, and says nothing about the order in which local
variables are allocated. Changing the order of declaration *might*
change the allocation order for some implementation; apparently it
doesn't for gcc.

If the behavior of your program depended on the order, then your
program would need to be corrected.
 
I

Ian Collins

Pete said:
Asking a gcc group was my second choice... and I dont REALLY care that
much. I was "working through" some examples in a C/assembly tutorial I
found online and it mentioned that by changing the order they were
defined in the source, you can change the order on the stack. It
wasn't really important, but since it didn't work it "perked" my
curiosity.
Such details are best left to the implementation.

The order is undefined by the standard and may change with different
options and optimisations with the same compiler. Local variables my be
optimised to registers and not appear on "the stack", assuming there is
one...

If you want a fixed order, use a struct.
 
C

Chris Torek

Is there a way to cause gcc to place local C variables onto the stack
in the order they are defined in the source code?

Yes: modify the compiler source. :)

(Seriously, gnu.gcc.help, or one of the mailing lists, is a better
place for gcc-specific questions. I do not know everything about
enough versions of gcc to say *for certain* that the answer to the
question I think you intended to ask -- ie, whether there are
compile-time flags and/or pragmas / and/or other existing mechanisms
to control this sort of thing, without modifying gcc itself -- is
"no", but I think that is the answer.)
I have been experimenting with how gcc converts C code to machine
code and have found that no matter how I define a function's local
variables, they are always stored in the same order on the stack.
[which you later note conflicts with a statement in a C tutorial]

The problem here is that the C tutorial you have been using is
wrong.

There is a general rule that applies here though, to all compilers
(not just gcc, and not just C compilers). *In general* (and there
will be exceptions), the "smarter" a compiler is, the less resemblance
you will find between "original source code" and "final machine-level
code". A compiler is simply a tool for taking a sort of "statement
of intent", represented in some source-code language, and turning
it into another, different, "statement of intent" -- normally in
some other, "lower level" language, such as assembler or machine
language -- that has the "same meaning" but is somehow "better"
for some particular purpose(s) (typically "execution speed", and
sometimes code size comes into play as well).

When the source language is "imperative" (statement or "command
sequence" oriented languages like C, Pascal, Fortran, Ada, etc.,
fall into this family) and "sequential" (most imperative languages
view execution as a "sequence of events", rather than some sort of
nondeterministic or parallel/simultaneous evaluation, although
there are some exceptions), the compilation process involves
analyzing the semantics of the sequence of "do this, then do that;
then, while condition X holds, do some other things" commands, and
finding an equivalent -- but preferably simpler, faster, etc --
sequence that achieves the same results. If the target language
is machine language, the final sequence is "machine instructions",
but one can (e.g.) compile things like C++ to C, as early C++
compilers did (though today, few use this path, for various reasons).

A "dumb" compiler will take your original source code constructs
and apply whatever small, simple, and obvious mappings are needed
to make the target language achieve the required results. So "do
step 1, then do step 2; then, while X holds, do steps 3 and 4"
generally becomes:

do step 1
do step 2
loop:
test X
if test fails, goto end_loop
do step 3
do step 4
goto loop
end_loop:

(since most target languages have this sort of label/goto ability).
A "smarter" compiler, however, may realize that "step 2" is mostly
redundant, and that step 3 never changes and it is OK to compute
it once, and produce:

do step 1
do a little bit of step 2
test X
if test fails, goto end_loop
temp = do step 3
loop:
use temp to pretend to do step 3
do step 4
test X
if test succeeds, goto loop
end_loop:

The more "smarts" the compiler can apply, the more of the original
code it can move, alter, remove, replace, or refine. The more this
sort of work is pushed towards the latest stages of "compiling"
(e.g., by doing code-generation at link time, when you do "xlink
foo.o bar.o baz.o" instead of when you do "xcompile foo.c"), the
more likely one is to find that entire functions have been moved
around, formal parameters replaced with their actual arguments,
constants propagated, swathes of unreachable code removed, and so
on. (The compilation will take much longer but the code may run
significantly faster. Of course, one tiny source-level change, to
replace a constant argument with a runtime input value, may require
putting all the removed code back again.)

All of the above may seem sort of abstract and theoretical, perhaps
because it *is*, but there is a key point here, and that is: the
most important part of your source code is not its *syntax* (the
spelling, word-order, and so on) but rather its *semantics* (the
things that every compiler is obliged to *do*, or at least "appear
to have done", when the code is run). The semantics are the
*meaning* of the code, and a compiler's job is to preserve this
meaning, not mere spelling. The syntax is not *irrelevant* -- it
matters a lot to human readers, who tend to use it as a shortcut
to understanding the language-provided semantics, and moreover, to
glean some additional "deeper meaning" that is not contained in
the source-code language[%] -- but it is not crucial to the
compilation, at least. (There are some languages, like Python, in
which syntax *is* semantically meaningful, though.)

(If anyone ever says something like "bah, mere semantics", you know
they have lost the argument. :) It seems a bit peculiar to me that
the word "semantics" is used in ordinary conversation to "refer to
a trivial point ... that revolves around mere words" [see
<http://dictionary.reference.com/browse/semantics>, when words are
often the only tool we have to communicate. If the words are all
we have, how can they be "mere"?)

[% This "deeper meaning" is the programmer's *intent*. Humans can
look at the names of variables and functions, and attempt to figure
out *why* you are looping six times here, or computing square roots
there. Of course, as a programmer, you should also consider writing
comments that explicate your intent. The source code will, via
the language's semantics, already say "what to do"; you should
endeavor to add "why I do it this way here". That is, you should
add even more semantic information, above and beyond that required
by the source-code language. You should aim this information at
whoever will work on your code in the future. Even if that person
is "yourself a year later", you may find it very useful.]
 
A

Antoninus Twink

Changing the order of declaration *might* change the allocation order
for some implementation; apparently it doesn't for gcc.

The most obvious reason for the compiler to rearrange the order of local
variables on the stack is to avoid wasting space unnecessarily if the
variables need different alignments. Of course, as someone else pointed
out the compiler can also sometimes eliminate local variables
completely, or store them in a register.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,192
Latest member
KalaReid2

Latest Threads

Top