1

I came across some code similar to the following:

uint8_t* dataPtr = {0};

switch(index)
{
  case 0:
    dataPtr = (uint8_t[32])
    {
        0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
        0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
        0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
        0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
    }
    break;
  case 1:
    dataPtr = (uint8_t[32])
    {
        0x43, 0x42, 0x41, 0x30, 0x29, 0x27, 0x38, 0x89,
        0x33, 0x22, 0x21, 0x30, 0x29, 0x27, 0x38, 0x89,
        0x33, 0x12, 0x31, 0x30, 0xAF, 0x27, 0x38, 0x89,
        0x33, 0x32, 0x55, 0x30, 0xFF, 0xFF, 0x38, 0x89,
    }
    break;

and so on...

The code as it's written seems to work. I do not understand how memory is not getting corrupted. The initial definition of dataPtr defines it as a pointer to an empty array of uint8_t with an unknown size. Then, it is casted to a static array of 32 uint8_t's and assigned data.

During the initial definition, how does the compiler know how much memory to allocate for this variable? Is this memory allocated on the stack during runtime? Somewhere else during compile time?

9
  • I don't understand how this compiles. Does your company use some kind of non-standard compiler extensions? Commented Apr 6, 2017 at 20:28
  • It is not being cast. All that's happening is that the pointer is being reassigned to point at a different array. Commented Apr 6, 2017 at 20:28
  • There is no cast in the code. What do you mean? And uint8_t* dataPtr = {0}; should be uint8_t* dataPtr = NULL;. Commented Apr 6, 2017 at 20:28
  • @Xirema: Why? It is standard C. Commented Apr 6, 2017 at 20:29
  • 1
    Calm it down. The tagging of C++ was simply a mistake, I wasn't being malicious. Commented Apr 6, 2017 at 20:33

2 Answers 2

5

These are compound literals. A feature added in the 1999 revision of C. But their use here reeks of undefined behavior.

(uint8_t[32])
{
    0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
    0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
    0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
    0x33, 0x32, 0x31, 0x30, 0x29, 0x27, 0x38, 0x89,
}

The above will create an anonymous array of 32 uint8_t. It's storage duration depends on the scope where it appears. And since it appears at block scope for the switch, dataPtr ends up pointing at an out of scope object whose lifetime has officially ended.

Or in standardese [C11 N1570 6.5.2.5p5]

The value of the compound literal is that of an unnamed object initialized by the initializer list. If the compound literal occurs outside the body of a function, the object has static storage duration; otherwise, it has automatic storage duration associated with the enclosing block.

Sign up to request clarification or add additional context in comments.

Comments

2

The variable dataPtr is just a pointer. Its size is the size of a pointer. You can however freely change what it points to.

At the start of the program, it points to a constant array with 1 element. Later, it is modified to point to a different constant array with 32 elements. These constants are already allocated (most likely in a read-only section of memory) at the time your program starts up.

The syntax that looks like a cast is actually a compound literal.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.