Using the ternary operator in the assignment below results in the incorrect value being assigned to the struct.
/// GPL 2.0 or later
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
typedef struct {
uint8_t x;
uint8_t y;
} maths_point_u4;
maths_point_u4 room1 = { 11, 12 };
const maths_point_u4 *RoomGet(void) { return &room1; }
static void PositionAdjust2( const maths_point_u4 *room, maths_point_u4 *room_new ) {
printf("*Room %p\n", room);
*room_new = room ? *room : *RoomGet();
}
void main( void ) {
maths_point_u4 room2 = { 5, 6 };
PositionAdjust2( 0, &room2 );
printf("Room1 %d, %d\n", room1.x, room1.y);
printf("Room2 %d, %d\n", room2.x, room2.y);
}
#ifdef __SDCC
__sfr __at 0xff sif;
int putchar( int c ) {
sif = 'p';
sif = c;
return c;
}
#endif
$ sdcc -mz80 --fverbose-asm ./assign_struct2.c -o assign_struct2.ihx && 0> Loading from assign_struct2.ihx
Simulation started, PC=0x000000
*Room 0x0000
Room1 11, 12
Room2 253, 43
$ gcc ./assign_struct2.c && ./a.out
*Room (nil)
Room1 11, 12
Room2 11, 12
SDCC : z80/sm83/z80n/mos6502/mos65c02/f8 TD- 4.5.2 #15451 (Linux)
I've simplified it.. Starting from:
The generated code of the function g is:
and the bad part is what happens after the
call _f. The correct code without unnecessary steps would be:Comparing with what we have now we see that the bad code does more than it should, and it's after the function call:
and there we see that it's clearly one unneeded dereference (like that dereference would get a 2-byte value, e.g. a pointer!) which doesn't match the rest of the code.
So the function returns a pointer to a structure, but somehow expression handles that part as if the function would return a pointer to a pointer to a structure, and dereferences that before a pointer is propagated to the common
result := *HL.Last edit: Janko Stamenović 2025-06-24
The relevant verbose part:
If the function would use a "workaround":
then the result would be correct, even if it's still one
ex de, hlmore than it would be optimal:verbose:
This test that tests three forms of the expression and both branches. Only !p in g1 fails currently.