4

I read that C holds the carry-out from shifts and it can be found in processor-specific .h.

Is this true and should I use it? or should work out the carry-out bit myself ?

cxzp
  • 652
  • 2
  • 14
  • 28
  • Maybe some asm inline works for that. – huseyin tugrul buyukisik May 31 '13 at 15:00
  • I'm curious as to your use case for checking the carry out. When done at the assembly level, it's generally a technique to check the value of bits in a register in sequence. There are other ways to do this in C that don't involve checking for a carry-out. If there's a processor-specific implementation for it, you don't gain much in performance unless you really need performance tweaks that register in the microseconds per iteration. – lurker May 31 '13 at 15:53

2 Answers2

8

There is no standard way to access the carry bit(s) of primitive operations in C.

You will either need to perform the shift in a larger data type:

uint16_t foo = ...;

uint32_t tmp = (uint32_t)foo << shift;
uint16_t result = (uint16_t)tmp;
uint16_t carry  = (uint16_t)(tmp >> 16);

or by performing the opposite shift:

uint16_t result = foo << shift;
uint16_t carry  = foo >> (16 - shift);

Note that this second method invokes undefined behaviour if shift == 0, so you'd need to handle that case separately.

Oliver Charlesworth
  • 267,707
  • 33
  • 569
  • 680
  • Yes, going to a larger data type is the best when its available. Note: The answers also invokes undefined behavior if 'shift <= 0' or 'shift >= 16'. Handling those cases though shouldn't be a great challenge though for anyone using your fine answer. – chux - Reinstate Monica May 31 '13 at 16:05
  • @chux: Thanks! However, `shift` < 0 or >= 16 is UB however you do it, whereas my 2nd method also means that `shift == 0` is UB as well. – Oliver Charlesworth May 31 '13 at 16:07
  • In review, I think the shift of `0` may be OK in the second method. Sure we both think `uint16_t result = foo << 0` OK? But is not `uint16_t carry = foo >> 16` defined? – chux - Reinstate Monica May 31 '13 at 16:51
  • You are correct sir! (*Ed McMahon) "If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined." `foo >> 16` is UB. I was stuck in 6.5.7 p4&5. – chux - Reinstate Monica May 31 '13 at 17:05
1

Standard C does not provide access to the carry-out from shifts.
Some, not all, C implementations have processor-specific.h files or other extensions that do allow access.

Your should avoid using functionality from processor-specific.h files or extensions where practical. But if obliged to use, consider also writing a C Standard solution, at least as part of the documentation. see Recommended @Oli Charlesworth solution.

In general, to create effective portable code, one may need to view the problem at a higher level and not use carry outs. On the other hand, if this is for a narrow range of machines, go with what works for you (or those that pay your wage).

Various weaknesses were pointed out in my earlier posted examples. I see these now as implementation dependent. There are deleted.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • You're right to say this borders on portability. Left-shifting negative values is undefined behaviour, which is anything but *portable*. Right-shifting negative values is implementation-defined behaviour, which might include sign preservation, if not now then at some point in the future. Both should be avoided. – autistic May 31 '13 at 16:25
  • @ undefined behaviour Agreed with your assessment of my "borderline" examples and have removed them. – chux - Reinstate Monica May 31 '13 at 17:35