1

I read the book CS:APP(Third Edition) and in Section 3.6.1 Condition Code. It says:

CF: Carry flag. The most recent operation generated a carry out of the most significant bit. Used to detect overflow for unsigned operations.

OF: Overflow flag. The most recent operation caused a two's-complement overflow--either negative or positive.

But I have the following code. I compiled and executed it. Something different happened.

int main() {
    char x  = 0x66;
    char y =  0x39;
    char x_bit_not = ~x;
    char x_not = !x;
    char x_bit_and_y = x & y;
    char x_and_y = x  && y;
    char  x_bit_or_y = x | y;
    char x_or_y = x || y;


    int x1 = (1<<31)-1;
    int y1 = 1;
    int sum_x1_y1 = x1 + y1;
    int diff_x1_y1 = x1 - y1;
    int diff_y1_x1 = y1 - x1;


    unsigned int x2 = (1<<31)-1;
    unsigned int y2 = 1;
    unsigned int sum_x2_y2 = x2 + y2;
    unsigned int diff_x2_y2   = x2 - y2;
    unsigned int diff_y2_x2   = y2 - x2;
}

The arithmatic expression int diff_y1_x1 = y1 - x1; yeilds 0x80000002 without a carry out from the msg. But after this statement, CF is equal to 1.

The arithmatic expression unsigned int sum_x2_y2 = x2 + y2; does not even involve signed variants but after this statement, OF is equal to 1. How does this happen?

Also, I have got another picture: enter image description here And the caption says CF = Cin XOR Cout and OF = Cn XOR Cn-1. What does this mean? Is CS:APP wrong? Or just CS:APP does not contain all the conditions?

Rivers Shall
  • 531
  • 1
  • 3
  • 13
  • 1
    When subtracting two positive numbers results in a negative number (`x1 - y1 = 0x80000002`), then the carry flag should be set (as you would carry when doing pen-and-pencil subtraction). When adding two positive numbers results in a negative number (`x2 + y2 = 0x80000000`), then that qualifies as an overflow (since a correct result exceeds the range of _signed_ 32-bit integer). Wouldn't you agree? – Ruud Helderman Jul 10 '18 at 09:24
  • The flag setting is done without regard to the sign of the operands (the processor does not know whether the operands are signed or unsigned), but the programmer or compiler then generates the appropriate condition testing various combinations of flags according to the operand type. – Weather Vane Jul 10 '18 at 09:34
  • C doesn't have flags. I assume you compiled that code for x86 with some compiler with optimization disabled, and then single-stepped it with a debugger? Beware that the compiler could have used an `lea` (which doesn't set flags) instead of an `add` instruction. You should really be looking at the asm you're stepping through instead of making assumptions about how your code compiled. (Unless you're already totally familiar with how your compiler generates code with optimization disabled...) – Peter Cordes Jul 10 '18 at 10:59
  • Your C code doesn't show any CF/OF. The x86 machine instruction `add` will update both CF and OF, while adding two values (8, 16, 32 or 64 bit). Whether the preceding/following code treats those bits as signed or unsigned integer is of no concert to the `add` itself, which does operate in the exact same way in both cases, so the CF and OF flags are set to some value for both signed and unsigned C math, and the following code must use the proper one. The flags have "correct" value when used in the "correct" context, else they've "wrong" value (but well defined). `-3 + -4` sets CF, but who cares – Ped7g Jul 10 '18 at 12:40

1 Answers1

2

My answer assumes x86. Other architectures might behave differently.

On x86, both CF and OF flags are impacted by signed and unsigned operations (because the CPU doesn't know the signed-ness). Which flag(s) are relevant depends on the specific use case. Typically, the CF flag is checked for unsigned arithmetic, while the OF flag is checked for signed arithmetic. See also : about assembly CF(Carry) and OF(Overflow) flag

Addressing your observations specifically :

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • Regarding to "add" there are not really "signed" and "unsigned" operations on x86. It is just an add operation, only the interpretation of the resulting flags makes the difference. The 2s complement representation of signed integers makes this possible. – Ctx Jul 10 '18 at 10:34
  • @Ctx : edited my answer to make that explicitly clear. – Sander De Dycker Jul 10 '18 at 10:51
  • `-1 - -2 => +1` doesn't set OF, but the MSB changed. See [simulate jg instruction(datalab's isGreater)](https://stackoverflow.com/q/51168010) for a table of input/output signs for subtraction, with the two OF cases labeled. – Peter Cordes Jul 10 '18 at 10:54
  • @PeterCordes : my answer assumed addition of 2 unsigned values for that statement. I've clarified it to avoid confusion. – Sander De Dycker Jul 10 '18 at 11:04
  • 1
    For the purposes of calculating OF, you have to interpret your inputs as signed, as well as your output. That's the whole point: OF tells you whether the signed operation wrapped; CF tells you whether the unsigned operation wrapped. OF would be super-weird if it interpreted its inputs as unsigned 0xFFFFFFFF and 0xFFFFFFFE: if it did, then add would set OF with those inputs, which is nonsense: `-1 + -2` doesn't overflow. (Your edit already fixed this.) – Peter Cordes Jul 10 '18 at 11:09
  • @PeterCordes : the observation of the OP was that when he added two `unsigned int`s (`x2 + y2`), OF was set. I was specifically addressing that observation when assuming addition of two unsigned values. While you're right that reasoning about the meaning of OF in that context is useless, that doesn't take away the fact that OF *is* set. – Sander De Dycker Jul 10 '18 at 11:15
  • C doesn't have flags, so this whole question is nonsense unless you boil it down to an x86 `add` with those inputs: INT_MAX and 1. OF is set because a signed interpretation of those bit-patterns is overflow. This is the whole point of the answer: x86 ADD/SUB always set flags based on both interpretations: CF for unsigned, OF and SF for signed. So you can't just simplify to "MSB changed", because the C type of the input makes no difference to the effect of feeding the bit-pattern to an `add` instruction. (You already fixed the answer, so IDK if it matters to distinguish clarification vs fix) – Peter Cordes Jul 10 '18 at 11:23
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/174715/discussion-between-sander-de-dycker-and-peter-cordes). – Sander De Dycker Jul 10 '18 at 11:25