English Amiga Board

English Amiga Board (http://eab.abime.net/index.php)
-   Coders. C/C++ (http://eab.abime.net/forumdisplay.php?f=118)
-   -   Is this legal C? (http://eab.abime.net/showthread.php?t=100066)

deimos 18 December 2019 10:08

Is this legal C?
 
Is this correct / legal C99, and will it do what I expect?

Code:


void AFunction(void) {
    WORD * kludge = NULL;

    // ...

    if (topLeft) {
        kludge = (WORD []) { 0, 1 };
    }

    // ....

    DoSomethingWith(kludge);
}

i.e. is the WORD [] containing the values 0 and 1 available outside of the scope of the if statement that it is declared in? Is it really allocated in the stack frame for the function, or does it end disappearing when the if statement completes, leaving kludge pointing to potential garbage?

hooverphonique 18 December 2019 10:57

Normally the compiler will reserve space on the stack for the array when you enter the function, then initialize it in the if-block, but I'm not sure if it could repurpose the stack space between the if-block and DoSomethingWith if you put some code there that requires space.

You could use a statically allocated array and assign its address to kludge instead.

deimos 18 December 2019 11:25

Quote:

Originally Posted by hooverphonique (Post 1365876)
it could repurpose the stack space

Ok, thanks, I won't risk it.

Edit:

Decided to use a struct instead:

Code:

typedef struct {
    BOOL required;
    WORD start;
    WORD end;
} Kludge;

void AFunction(void) {
    Kludge kludge = { .required = FALSE };

    // ...

    if (topLeft) {
        kludge = (Kludge) { TRUE, 0, 1 };
    }

    // ....

    DoSomethingWith(kludge);
}


phx 18 December 2019 17:32

Quote:

Originally Posted by hooverphonique (Post 1365876)
but I'm not sure if it could repurpose the stack space between the if-block and DoSomethingWith if you put some code there that requires space.

No. That shouldn't happen.

a/b 18 December 2019 18:13

Yeah, it's legal. It's the same as:
Code:

char* x = NULL;
if (...) {
  x = "whatever";
}
y(x);

The value you assign is anonymous static const, it's fully known at compile time, and it's not placed on stack. It's either placed in the object's data segment and then merged with others by linker (subject to segment manipulation directives), or embedded into code e.g if it fits in 32 bits and some optimizations take place. More or less, but in any case it's safe, in c99 or any other version.

deimos 18 December 2019 18:16

Quote:

Originally Posted by phx (Post 1365957)
No. That shouldn't happen.

What should happen to the { 0, 1 }? Where is it? In the functions stack frame? Or is it created within the if statement's block?

deimos 18 December 2019 18:27

Quote:

Originally Posted by a/b (Post 1365967)
Yeah, it's legal. It's the same as:
Code:

char* x = NULL;
if (...) {
  x = "whatever";
}
y(x);

The value you assign is anonymous static const, it's fully known at compile time, and it's not placed on stack. It's either placed in the object's data segment and then merged with others by linker (subject to segment manipulation directives), or embedded into code e.g if it fits in 32 bits and some optimizations take place. More or less, but in any case it's safe, in c99 or any other version.

Right. That makes sense, I recognise those words, but it only works if it's really a constant:

Code:

    kludge = (WORD []) { x, y };
Isn't legal, right?

phx 18 December 2019 18:50

Quote:

Originally Posted by a/b (Post 1365967)
Yeah, it's legal. It's the same as:
Code:

char* x = NULL;
if (...) {
  x = "whatever";
}
y(x);


Not really. Here you are just assigning x with a constant string pointer. This string is usually not temporarily allocated on the stack.
Deimos' example is some C99-thing. It doesn't work with C89.

Quote:

Originally Posted by deimos (Post 1365968)
What should happen to the { 0, 1 }? Where is it? In the functions stack frame? Or is it created within the if statement's block?

It's in the stack frame, allocated on function entry.

Quote:

Originally Posted by deimos (Post 1365969)
Code:

    kludge = (WORD []) { x, y };
Isn't legal, right?

Didn't test it, but I would guess it works. The structure is initialized during the if-statement, so its contents might also be variable (?).

a/b 18 December 2019 18:54

It's still safe. In this case a temporary object will be constructed on stack but its scope is *not* limited to if's {} (it's limited to current function).
Code:

WORD* p_array = NULL;
WORD  x = 1, y = 2;
if (...) {
  p_array = { x, y };  // OK
}
if (...) {
  WORD a = 1, b = 2;
  p_array = { a, b };  // bad, a and b are limited to if's {}
}
foobar(p_array);

The second case will still work though, because a temporary object on stack is valid and containts valid data because data type is WORD and is entirely copied into the object, and not something more complex (that includes pointers or references) that would cause dangling pointers/references. But it's bad and would be called out by compiler (but if you can get past that it should work).

jotd 18 December 2019 19:04

it's safe only when you're assigning a literal to your pointer. Else, if the area pointed to goes out of scope, anything can happen.

a/b 18 December 2019 19:34

Quote:

Originally Posted by phx (Post 1365978)
Not really...

Hmm, you're right. Such arrays (and structs) are constructed in run-time on stack.
I'm sure I knew that at some point, spoiled by not bothering much about such details in c++, and doing whatever I want in asm ;P.

alkis 18 December 2019 20:58

It's on stack (variable) on gcc-6.5
https://franke.ms/cex/z/A1khyA

On gcc-2.9.5 it's on data segment.

hooverphonique 18 December 2019 21:51

String literals are a special case, and they become heap-allocated objects.

You could use compiler explorer (e.g. godbolt.org) to check this kind of thing with different compilers and options.

Edit: or the link alkis provided, which has an m68k version of gcc, if you prefer that (strange that the array initialization is missing when selecting gcc 10, btw).

bebbo 05 January 2020 11:26

Quote:

Originally Posted by alkis (Post 1366002)
It's on stack (variable) on gcc-6.5
https://franke.ms/cex/z/A1khyA

On gcc-2.9.5 it's on data segment.


I consider this as wrong, since it's not const. If DoSomethingWith modifies a value subsequent calls will start with the modified values.




All times are GMT +2. The time now is 06:51.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2020, vBulletin Solutions Inc.

Page generated in 0.04510 seconds with 11 queries