Question

Consider following piece of C code -

char sum_char(char a,char b)
{
   char c = a+b;
   return c;
}

It involves -

  1. Convert second parameter to sign extension.
  2. Push signed extension parameter on stack as b.
  3. Convert first parameter to sign extension.
  4. Push signed extension parameter on stack as a.
  5. Add a & b, result cast to char and store it in c.
  6. C is again sign extended.
  7. Sign extended c is copied to return value register and function return to caller.
  8. To store result caller function again convert int to char.

My questions are -

  1. Who does this ?
  2. What is necessity of doing so many conversions ?
  3. Will it reduce/increase the performance of machine/compiler ?
  4. If it is reducing performance what should we do in order to increase it ?
Was it helpful?

Solution

  1. Who does this? - Ultimately, it's the CPU who does this; the compiler generates all the relevant instructions for the CPU to perform the conversions
  2. What is necessity of doing so many conversions? - The conversions are necessary to ensure consistency of the results across multiple platforms supported by multiple C compilers.
  3. Will it reduce/increase the performance of machine/compiler? - This will reduce the performance compared to "doing nothing", but nobody will notice the difference.
  4. If it is reducing performance what should we do in order to increase it? - Nothing: if you must perform arithmetic operations on chars, then you perform arithmetic operations on chars. Let the optimizer take care of removing all unnecessary instructions for your platform. In most cases, CPU has instructions that are compatible with the semantic required by the C language, so the generated code will be very short.

Of course if you do not need to perform operations on signed characters, you can perform operations on unsigned characters. This eliminated a good deal of sign extending.

OTHER TIPS

The conversions that you describe are only performed in the abstract machine. A compiler can shortcut all this if it leads to the same observable behavior.

When switching on optimizations my compiler translates this to the following assembler

sum_char:
.LFB0:
    .cfi_startproc
    leal    (%rsi,%rdi), %eax
    ret
    .cfi_endproc
.LFE0:
    .size   sum_char, .-sum_char

which is just one addition (hidden in the leal instruction) and a ret jump.

  1. The code, when run. The compiler generates the needed code to implement the specified semantics for the programming language.
  2. I'm not sure in the pushing to "stack" you're talking about, there's no such requirement in C as far as I know.
  3. That doesn't make sense; compared to what?
  4. You can try removing the pointless c variable, and just have return (char) (a + b);. That said, I don't think there's much to be "optimized" in this function. It should compile to very little code. If you can get it inlined, it will probably be on the order of 1 instruction.

I'm unsure as to the detail of your question. You refer repeatedly to sign-extension without citing any source; I guess you're assuming that the char data type will be extended to match the bit-ness of the CPU, but I don't think there's any guarantee that this is not the case already.

However, as a stab at answering your vague questions:

  1. The compiler does this in reponse to you writing the code. Who writes the code? A developer, I would imagine. You did this, when you wrote the question.
  2. If there is a necessity (for you don't cite your source), I imagine it is so that the CPU can handle the arithmetic natively.
  3. Technically it would reduce it, but only compared to a theoretical machine that has arbitrary bit-ness. Realistically, it makes no noticeable difference.
  4. There is a very slight performance gain if you use data types that match the native bit-ness of your architecture. However, this is very slight, and is usually not worth the inconvenience.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top