0

i am using avrx to build a software run on custom tiny device, but i'm still newbie to C. As indicated by makefile, it's using "c99 plus GCC extensions". Today i finally ran into a piece of code written by some old colleague, it made me very confused:

#define SOMEDATA    "ABC"
void main(void)
{
    memcpy(SOMEDATA, "OK", sizeof("OK"));
    printf(SOMEDATA);//it works just fine?!?!?  

    memcpy(SOMEDATA, "VERY_LONG", sizeof("VERY_LONG"));
    printf(SOMEDATA);//well, now it go nuts. all i see is some random data.
}

Why? Why the logic in main() behaved like that? I used to thought that MACROs acts like constant and cannot be modified.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261

2 Answers2

2

In your code

  memcpy(SOMEDATA, "OK", sizeof("OK"));

which is the same as

  memcpy("ABC", "OK", sizeof("OK"));

is a very unusual way of attempting to modify a string literal. It causes undefined behavior. Same as in the other case and, as we know, the outcome of UB is, well, anything.

That said,

   printf(SOMEDATA);

may be valid but a poor practice, if there's no conversion required, safer to use puts() or fputs().

Finally,

I used to thought that MACROs acts like constant and cannot be modified.

Well, probably you're interested in #define statements. #define statements are textual replacements which takes place at compile time. In case, a literal (or constant) value is used as a define statement, yes, it cannot be changed (following the property of a constant or literal) but in case, a define statement defines a variable name, then that variable, if a modifiable lvalue, can be modified for sure.

TL;DR #define statements are textual replacement, and their alteration depends on the element in replacement list.

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
1

This quote from the C Standard (6.4.5 String literals) will be useful for you

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

The first statement of the quote says that two string literals with the same values can be stored in the static memory either as distinct arrays or as the same one array,

So in fact this expression in the condition of the if statement

#define SOMEDATA    "ABC"

//...

if ( SOMEDATA == SOMEDATA )
{
    //...
}

can yield either true or false depending on the settings of options of the compiler.

That is these two calls of memcpy

memcpy(SOMEDATA, "OK", sizeof("OK"));
//..
memcpy(SOMEDATA, "VERY_LONG", sizeof("VERY_LONG"));

that are equivalent to

memcpy("ABC", "OK", sizeof("OK"));
//..
memcpy("ABC", "VERY_LONG", sizeof("VERY_LONG"));

can write either to the same extent of memory or to different extents of memory.

The second statement of the quote says that any attempt to change a string literal results in undefined behavior of the program.

Take into account that according to the C Standard the function main without parameters used in a hosted environment shall be declared like

int main( void )
^^^^

Though some compilers as the Microsoft compiler allows to use the type void as the return type of main it is better to follow the C Standard.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335