Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can sign/zero extension be accomplished just by casting?

I have a homework problem (MIPS simulator) which requires for example that we take a 16-bit "immediate" value and sign and/or zero extend it to 32-bits. I was under the impression that this could be easily accomplished just by casting, such as:

uint32_t imm = (uint16_t)IMM_FIELD(instruction); # Zero extend to 32-bits

and

uint32_t imm = (int16_t)IMM_FIELD(instruction); # Sign extend to 32-bits

But then I came across a piece of code online where someone who worked on the same project had written their own "sign_extension8to16", "sign_extension16to32" functions, and these functions worked by shifting the 8 bit number right by 7 and evaluating whether or not the most significant bit (now in the one's place) was 1, then returning a number that is casted to (uint16_t) which masks the upper 8 bits to 0 or 1 accordingly.

Is such an approach really necessary? I thought that surely casting took care of this already. The reason I ask is that I'm having very strange error messages and I can't pinpoint the problem, so I figure the reason might be that I'm incorrectly zero and sign extending...

like image 456
CptSupermrkt Avatar asked Nov 10 '22 09:11

CptSupermrkt


1 Answers

IMO: your method will work.

Let's simplify the problem.

The promotion of uint16_t to uint32_t and the promotion of int16_t to int32_t is easy to understand and the expected results occur. Zero fill unsigned integers and sign extend signed integers.

int main() {
  uint16_t u = 65535;
  int16_t i = -1;
  printf("%" PRIu32 "\n", (uint32_t) u);
  printf("%" PRId32 "\n", (int32_t) i);
  return 0;
}

65535
-1

The promotion of int16_t to uint32_t will first promote the int16_t to a int32_t and then to a uint32_t. (Actually I think it promote first to int16_t to int to int32_t and then to a uint32_t if sizeof int <= sizeof int32_t .) Thus code does a sign-extension before making the result an unsigned integer.

The promotion of uint16_t to int32_t will promote the uint16_t directly to a int32_t. A simple zero extension.

Note: I could be using "promote", when I should say "convert".

int main() {
  uint16_t u = 65535;
  int16_t i = -1;
  printf("%" PRIu32 "\n", (uint32_t) i);
  printf("%" PRId32 "\n", (int32_t) u);
  return 0;
}

4294967295
65535
like image 50
chux - Reinstate Monica Avatar answered Nov 15 '22 09:11

chux - Reinstate Monica