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.

13
  • C doesn't have the concept of a stack. There are just variables, and stacks are implementation details. Commented May 10, 2021 at 19:50
  • This is not a declaration. This is a definition. It's just that initial value of it is indeterminate. Commented May 10, 2021 at 19:51
  • definition is doing int a = 5. Commented May 10, 2021 at 19:52
  • 1
    @EugeneSh.: Every definition in C is a declaration. Nothing can be a definition and not a declaration. Commented May 10, 2021 at 20:18
  • 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. Commented May 10, 2021 at 20:46

3 Answers 3

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;
Sign up to request clarification or add additional context in comments.

8 Comments

sorry changed it to char.
@Dan don't change your question. It invalidates answers already provided.
so is it safe to say, only declaring a variable here puts it on the stack hence getting its address is valid?
@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.
@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.
|
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.

8 Comments

sorry changed it to char.
ok so is it safe to say, only declaring a variable here puts it on the stack hence getting its address is valid?
@Barmar It was a typo.:)
@Dan Why getting an address can not be valid? You declared (and defined) an object.
I don't know, I thought only declaring it might make passing its address to memset UB, C is weird in that.
|
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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.