0

so I'm trying to shift these values left to store all this data into a 64 bit value. Unfortunately the numbers turn negative right at the first shift, what's causing this? Isn't it only suppose to store the first 41 bits of mil_t time into x? Also why would the remainder of serial and userid be zero?

long int gen_id(){ printf("Calling gen_id...\n"); unsigned long int mil_t = 1623638363132; unsigned long int serial = 10000; unsigned int rowId = 5; unsigned int userId = 30000; printf("Original mil_t: %ld\n", mil_t); unsigned long int x = mil_t << 41; printf("GEN_ID | MIL_T shift left 41: %ld\n", x); unsigned long int tbusMod = userId % serial; printf("GEN_ID | tbusMod = userId mod serial: %ld\n", tbusMod); x += tbusMod << (64 - 41 - 13); printf("GEN_ID | x1 : %ld\n", x); x += (rowId % 1024); printf("GEN_ID | x2 : %ld\n", x); return x; } 

OUTPUT:

Original mil_t: 1623638647191 GEN_ID | MIL_T shift left 41: -4136565053832822784 GEN_ID | tbusMod = userId mod serial: 0 GEN_ID | x1 : -4136565053832822784 GEN_ID | x2 : -4136565053832822779 FINAL: -4136565053832822779 TOTAL BYTES: 68 
2
  • 3
    %lu is the conversion specifier for unsigned long, you are printing as a signed value... Commented Jun 14, 2021 at 2:54
  • When looking at the low-order bits of an integer, it's more standard to just use bitwise AND rather than the remainder operator, i.e. instead of rowId % 1024, just do rowid & 0x3ff. In the case of an unsigned operand, the compiler will probably do this anyway as an optimization, but I prefer not to use the remainder operator in the first place. If the operand is signed, then the compiler may need to do additional work to handle a negative operand when replacing the % operator. Commented Jun 14, 2021 at 3:48

1 Answer 1

2

Your program causes undefined behaviour by using the incorrect format specifier. %ld is only for long int (and not unsigned long int).

Instead use %lu to display x and tbusMod.


30000 divided by 10000 gives quotient 3, remainder 0 .

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

6 Comments

I see, I also figured out what's going on. I shouldn't be using long unsigned ints for this, but rather just regular unsigned ints, because I'm shifting the bits of the entire length of the integer. Appreciate it
Technical violation is correct, but since the size is the same, the result is seeing the signed interpretation instead of unsigned.
@Preston that comment doesn't make much sense but bear in mind that if you are using a 32-bit unsigned int then it would be undefined behaviour to shift by 41. Shift is only well-defined for fewer bits than the width of the type
@Preston maybe things will be slightly clearer if you work in hex (e.g. output with %lx , and use a hex constant for mil_t)
You can't store the constant 1623638363132 in a 32-bit unsigned int accurately; you'll lose a number of the most significant bits. You can't use mil_t << 41 unless sizeof(mil_t) * CHAR_BIT > 41 (so it needs to be a 64-bit unsigned integer, which means unsigned long long on Windows and unsigned long on Unix.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.