0

Is this valid C code without undefined behaviour?

int main(){
 int a;
 memset(&a, 5, sizeof(int));

 return a;
}

I'm assuming this is equal to just doing int a = 5.

I'm trying to understand if just declaring a variable in the above example (without defining it) is enough to put it on the stack.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Dan
  • 2,694
  • 1
  • 6
  • 19
  • C doesn't have the concept of a stack. There are just variables, and stacks are implementation details. – Barmar May 10 '21 at 19:50
  • This is not a declaration. This is a definition. It's just that initial value of it is indeterminate. – Eugene Sh. May 10 '21 at 19:51
  • definition is doing `int a = 5`. – Dan May 10 '21 at 19:52
  • No. It is definition with initialization. – Eugene Sh. May 10 '21 at 19:53
  • I'm rolling back the edit because the original question was answered; those subsequent edits invalidated the answers. – Adrian Mole May 10 '21 at 19:53
  • then what's the declaration? I thought `char a;` is only a declaration. – Dan May 10 '21 at 19:53
  • Why does it matter if it gets put on the stack? All that matters is that the result matches the specification. An optimizing compiler could translate the whole function to `return 5;` – Barmar May 10 '21 at 19:55
  • Actually `return 0x05050505;` – Barmar May 10 '21 at 20:01
  • I'm still confused about the above comment saying `It is definition with initialization.`? that makes no sense, this is clearly only a declaration without definition. – Dan May 10 '21 at 20:04
  • https://stackoverflow.com/questions/19326789/variable-declaration-vs-definition , https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration?rq=1 – Eugene Sh. May 10 '21 at 20:10
  • 1
    @EugeneSh.: Every definition in C is a declaration. Nothing can be a definition and not a declaration. – Eric Postpischil May 10 '21 at 20:18
  • @Eric Nice. Can we have a formal definition of a declaration? :-) – Adrian Mole May 10 '21 at 20:21
  • 1
    @AdrianMole: It is in C 2018 6.7. Primarily, it is a list of declaration specifiers followed by a list of declarators with, optionally, initializations, followed by a semicolon. – Eric Postpischil May 10 '21 at 20:46

3 Answers3

3

Is this valid C code without undefined behaviour?

Yes – Once the a variable has been declared in a given scope (like a function or other { ... } delimited block), it is valid to take its address and access the variable using that address within that scope (as your memset call does). An attempt to use that address when that scope has ended (i.e. is no longer 'active') will cause undefined behaviour; for example, the following is UB:

int main()
{
    int* p;
    { // New scope ...
        int a;
        p = &a; // Pointer to "a" is valid HERE
    } // The scope of "a" (and its 'lifetime') ends here
    memset(p, 5, sizeof(int)); // INVALID: "p" now points to a dead (invalid) variable
}

However, there's a major caveat in your code sample …

I'm assuming this is equal to just doing int a = 5.

There's the rub: It's assigning 5 to each component byte of the a variable, so it's doing this (assuming a 4-byte int):

int a = 0x05050505;

Which is the same as:

int a = 84215045;
Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • sorry changed it to `char`. – Dan May 10 '21 at 19:52
  • 2
    @Dan don't change your question. It invalidates answers already provided. – Roberto Caboni May 10 '21 at 19:53
  • so is it safe to say, only declaring a variable here puts it on the stack hence getting its address is valid? – Dan May 10 '21 at 19:57
  • @Dan Yes: Once a variable has been declared in a given scope (function or other `{ ...}` delimited block), taking its address (and using it, mostly) is valid. – Adrian Mole May 10 '21 at 19:59
  • @AdrianMole thanks, could you post an answer on this and I will accept it, every other answer is focusing on the data type mistake I had. – Dan May 10 '21 at 20:00
  • @Dan In the context of a local variable, the difference between *declaration* and *definition* is semantic. Here's a good read: [What is the difference between a definition and a declaration?](https://stackoverflow.com/q/1410563/10871073). – Adrian Mole May 10 '21 at 20:12
  • Re “An attempt to use that address from *outside that scope* will cause undefined behaviour”: `void foo(void *p) { p; } int main(void) { int a; foo(&a); }` uses the address of the object named `a` outside the scope of the identifier `a`, but the behavior is fully defined. – Eric Postpischil May 10 '21 at 20:48
  • @Eric Accurate and precise (as ever). See edit. (I blame the new font.) – Adrian Mole May 10 '21 at 20:50
2

From the C Standard (7.23.6.1 The memset function)

2 The memset function copies the value of c (converted to an unsigned char) into each of the first n characters of the object pointed to by s.

So this call

memset(&a, 5, sizeof(int));

does not set the variable a equal to 5. Internally the variable will look like

0x05050505

Here is a demonstrative program

#include <stdio.h>
#include <string.h>

int main(void) 
{
    int a;
    
    memset( &a, 5, sizeof( int ) );
    
    printf( "%#x\n", ( unsigned )a );
    
    return 0;
}

Its output is

0x5050505

You should use the function memset with integers with caution because in general it can produce a trap value. Also the result depends on how internally integers are stored starting from MSB or LSB.

P.S. You declared a variable inside a block scope with no linkage. It is also a variable definition that has automatic storage duration. As the variable explicitly was not initialized then it has an indeterminate value. You may apply the address of operator & to get the address of the memory extent where the variable is defined.

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

That's not undefined behavior. The problem is that it doesn't what you expect.

The result of

memset(&a, 5, sizeof(int));

consists in setting to 5 each of the four bytes of your integer a.

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39