Constant Data in function copied to stack

T

Thomas Matthews

Hi,

I've found with my compiler, that when a function contains const
data in a function, that data is first copied to the stack[1].

Given:
/* Example 1 */
char Buffer[1024];

void My_Func(void)
{
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};
memcpy(Buffer, TEXT, sizeof(TEXT));
return;
}

My compiler copies the data in TEXT to some memory location,
then passes a pointer to that location to the memcpy routine.

If I move the declaration to outside of the function:
/* Example 2 */
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};

void My_Func(void)
{
memcpy(Buffer, TEXT, sizeof(TEXT));
return;
}


or label it as static (and keep it in the function):
/* Example 3 */
void My_Func(void)
{
static const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};
memcpy(Buffer, TEXT, sizeof(TEXT));
return;
}

then the compiler passes a pointer to the text to memcpy,
without making an interim copy.

Here are my questions:
Q1: Is the interim duplication mandated by the C language
specification or is this a problem with my compiler?

Q2: Is the _static_ modifier supposed to have this effect?

Q3: My understanding is that constant data is placed into
a constant area and not copied. Am I wrong?

I'm working on an embedded system and I don't want a duplicate
copy of the data created. In our system, we've replaced
memcpy with memcpy_byte (our proprietary function) and we don't
want the library version invoked, which is what the compiler
does in Example 2.

------
[1] Yes, I know that the standard doesn't require implementations
to have a stack, call it read/write memory if "stack" bothers
you.


--
Thomas Matthews

C++ newsgroup welcome message:
http://www.slack.net/~shiva/welcome.txt
C++ Faq: http://www.parashift.com/c++-faq-lite
C Faq: http://www.eskimo.com/~scs/c-faq/top.html
alt.comp.lang.learn.c-c++ faq:
http://www.raos.demon.uk/acllc-c++/faq.html
Other sites:
http://www.josuttis.com -- C++ STL Library book
 
J

Jeremy Yallop

Thomas said:
I've found with my compiler, that when a function contains const
data in a function, that data is first copied to the stack[1].

Given:
/* Example 1 */
char Buffer[1024];

void My_Func(void)
{
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};

This instructs the compiler to create an automatic variable of type
"array of 6 char". If instead of calling "memcpy", you were passed
the address of this function to another function defined elsewhere
then the compiler would have no way of knowing that there is only one
copy of TEXT active at any time, so it would be obliged

#include <stdio.h>

void My_Func(void);
void function(const char *text)
{
static const char *saved;
if (!saved) {
saved = text;
My_Func();
}
else {
printf("Second call: %d %s %s\n", saved == text, saved, text);
}
}

void My_Func(void)
{
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};
function(TEXT);
}

int main()
{
My_Func();
return 0;
}

The output of this program is:

Second call: 0 Hello Hello

The second time 'function' is called, the pointers 'saved' and 'text'
each point to a valid, active variable called 'TEXT', one in each
active invocation of 'My_Func'. The C standard requires that these
two variables have distinct addresses, so the compiler is obliged to
create two copies.
memcpy(Buffer, TEXT, sizeof(TEXT));

Since memcpy() is a standard function, the compiler has special
knowledge; it knows that memcpy() doesn't capture the value of the
source pointer and that it doesn't invoke 'My_Func' recursively, so it
could legitimately create only a single, static copy of 'TEXT' as an
optimization. As it happens, that optimization is entirely
unnecessary, because there are at least two ways for the programmer to
indicate that only a single copy is desired. Both involve objects
with static storage duration:

void My_Func(void)
{
const char *TEXT = "Hello";

This creates an unamed static array of char and assigns the address of
the first element to the variable 'TEXT'.

void My_Func(void)
{
static const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};

This creates a named array of char with static storage duration. In
both of these cases there is only one object involved, and there is no
reason for any compiler to make unwanted copies. I think that answers
all of your questions, but just to be clear:
Here are my questions:
Q1: Is the interim duplication mandated by the C language
specification or is this a problem with my compiler?

No. The duplication is mandated unless the compiler can prove that
there is no way for a strictly conforming program to tell whether or
not a copy was made.
Q2: Is the _static_ modifier supposed to have this effect?

Yes.
Q3: My understanding is that constant data is placed into
a constant area and not copied. Am I wrong?

Yes.

Jeremy.
 
J

Jeremy Yallop

Thomas said:
I've found with my compiler, that when a function contains const
data in a function, that data is first copied to the stack[1].

Given:
/* Example 1 */
char Buffer[1024];

void My_Func(void)
{
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};

This instructs the compiler to create an automatic variable of type
"array of 6 char". If instead of calling "memcpy", you were to pass
the address of TEXT to another function defined elsewhere then the
compiler, with no way of knowing that there is only one active copy
accessible at any time, would be obliged to actually allocate a new
variable on each call to the function.

#include <stdio.h>

void My_Func(void);
void function(const char *text)
{
static const char *saved;
if (!saved) {
saved = text;
My_Func();
}
else {
printf("Second call: %d %s %s\n", saved == text, saved, text);
}
}

void My_Func(void)
{
const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};
function(TEXT);
}

int main()
{
My_Func();
return 0;
}

The output of this program is:

Second call: 0 Hello Hello

The second time 'function' is called, the pointers 'saved' and 'text'
each point to a valid, active variable called 'TEXT', one in each
active invocation of 'My_Func'. The C standard requires that these
two variables have distinct addresses, so the compiler is obliged to
create two copies.
memcpy(Buffer, TEXT, sizeof(TEXT));

Since memcpy() is a standard function, the compiler has special
knowledge; it knows that memcpy() doesn't capture the value of the
source pointer and that it doesn't invoke 'My_Func' recursively, so it
could legitimately create only a single, static copy of 'TEXT' as an
optimization. As it happens, that optimization is entirely
unnecessary, because there are at least two ways for the programmer to
indicate that only a single copy is desired. Both involve objects
with static storage duration:

void My_Func(void)
{
const char *TEXT = "Hello";

This creates an unamed static array of char and assigns the address of
the first element to the variable 'TEXT'.

void My_Func(void)
{
static const char TEXT[] = {'H', 'e', 'l', 'l', 'o', '\0'};

This creates a named array of char with static storage duration. In
both of these cases there is only one object involved, and there is no
reason for any compiler to make unwanted copies. I think that answers
all of your questions, but just to be clear:
Here are my questions:
Q1: Is the interim duplication mandated by the C language
specification or is this a problem with my compiler?

No. The duplication is mandated unless the compiler can prove that
there is no way for a strictly conforming program to tell whether or
not a copy was made.
Q2: Is the _static_ modifier supposed to have this effect?

Yes.
Q3: My understanding is that constant data is placed into
a constant area and not copied. Am I wrong?

Yes.

Jeremy.
 
L

lawrence.jones

Thomas Matthews said:
Here are my questions:
Q1: Is the interim duplication mandated by the C language
specification or is this a problem with my compiler?

Neither. The compiler is at liberty to treat such an array as if it
were static (because any attempt to modify it results in undefined
behavior), but is under no obligation to do so, nor would most
programmers expect it to.
Q2: Is the _static_ modifier supposed to have this effect?

Yes. Conceptually, automatic variables are created (and initialized)
each time the containing block is entered and destroyed when the block
is exited; static variables are conceptually created at program startup
and destroyed at program end. Your compiler (like most compilers) is
implementing this concept literally -- allocating space (on the stack)
each time the block is entered and initializing it to the correct
values even though this particular automatic variable is declared const.
Q3: My understanding is that constant data is placed into
a constant area and not copied. Am I wrong?

Yes. Defining an object as const simply indicates that you do not
intend to modify it. It does not oblige the compiler to prevent you
from modifying it or to perform optimizations based on it not being
modifiable.

-Larry Jones

He just doesn't want to face up to the fact that I'll be
the life of every party. -- Calvin
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,056
Latest member
GlycogenSupporthealth

Latest Threads

Top