Reputation: 838
I have a struct:
typedef struct cbor {
cbor_type type;
uint64_t length; //x2 for maps
struct cbor* child;
struct cbor* next;
struct cbor* parent;
union {
const uint8_t* bytes;
long sint;
uint64_t uint;
double real;
} value;
} cbor;
I initialize a pointer to cbor with malloc, and set length to 0, and value uint and sint to 1, and type to CBOR_INTEGER.
I have a function that should print info about cbor struct:
void cbor_print_item(cbor* item){
os_printf("c2 = %d %d %d\n", item->value.sint, item->value.uint, item->length);
switch(item->type){
case CBOR_INTEGER:
os_printf("type:integer\nsval:%d\nuval:%d\nlength:%d\n", item->value.sint, item->value.uint, item->length);
os_printf("type:integer\n");
os_printf("sval:%d\n", item->value.sint);
os_printf("uval:%d\n", item->value.uint);
os_printf("length:%d\n", item->length);
break;
case CBOR_STRING:
os_printf("type:\tstring\n");
os_printf("val:\t%s\n", item->value.bytes);
os_printf("length:\t%d\n", item->length);
break;
case CBOR_REAL:
os_printf("type:\treal\n");
os_printf("length:\t%d\n", item->length);
os_printf("val:\t%f\n", item->value.real);
break;
default:
os_printf("error!\n");
}
}
However, I don't get the expected output. The output for printf's in switch should be the same, right? My output is:
c2 = 1 1 0
type:integer
sval:1
uval:1
length:0
type:integer
sval:1
uval:144
length:144
I'm writing code for espressif, hence the "os_printf", as far as I know, it work as "printf".
I'm really baffled and cant find out why this is happening.
EDIT 1: I know that I shouldn't use "%d" for long and uint64. The question is why are the outputs different? I don't change the values between printing, so the same values should be printed.
EDIT 2: This question isn't about unions, their initialization, best way of printing uint64 or long.
The question is why does
os_printf("type:integer\nsval:%d\nuval:%d\nlength:%d\n", item->value.sint, item->value.uint, item->length);
type:integer
sval:1
uval:1
length:0
and
os_printf("type:integer\n");
os_printf("sval:%d\n", item->value.sint);
os_printf("uval:%d\n", item->value.uint);
os_printf("length:%d\n", item->length);
prints
type:integer
sval:1
uval:144
length:144
Upvotes: 1
Views: 232
Reputation: 7324
You have undefined behavior because you are trying to print a uint64_t
using the %d
format. printf
(and other functions that take a variable number of arguments) needs to know the type (and size) of the arguments. It gets this information from the format specifiers. Because you gave it %d
instead of the correct format it's trying to read an int
instead of a uint64_t
. See this as an example.
Upvotes: 4
Reputation: 6070
with sprintf(format, val1, val2)
you put val1 and val2 on the paramter stack to sprintf, and then sprintf will fetch values from that stack according to the format string, which is blindly running over the values, not knowing the actual sizes.
so in quintessenz: undefined behaviour
Upvotes: 0