-1

I was just experimenting and I tried out two printf()s.

unsigned char a = 1;
a = ~a;
printf("----> %x %x %x %x", ~a, a, ~a, ++a);

This one gave the output

----> ffffff00 ff ffffff00 ff

Next one was

unsigned char a = 1;
printf("----> %x %x %x %x", ~a, a, ~a, ++a);

This one gave the output

----> fffffffd 2 fffffffd 2

Now, I know what '++' does and '~' does. I also know that the sequence of operation inside printf is from the right.

But could some one explain the difference in the number of bytes printed? A total explanation of output would be helpful of course, but I am more interested in the number of bytes and the difference in both cases [especially in the printf a and ~a parts].

EDIT:

OK, looks like the ++ part and my mistake of "I also know that the sequence of operation inside printf is from the right" has prompted every post other than the answer I was hopefully looking for. So may be the way I asked was wrong.

I will try again,

unsigned char a = ~1;
a = ~a;
printf("----> %x", a); 

OUTPUT: ----> 1

unsigned char a = ~1;
printf("----> %x", ~a);

OUTPUT: ----> ffffff01

Why this difference?

Tattu
  • 327
  • 1
  • 3
  • 15
  • 5
    "I also know that the sequence of operation inside printf is from the right." - yes, that's what you're likely to see but that's not something you should generally rely on. Technically the sequence here is undefined. – Rup Dec 09 '15 at 11:53
  • 3
    " I also know that the sequence of operation inside printf is from the right." Than it is incorrect what you know. – dhein Dec 09 '15 at 11:53
  • Also `%x` expects `unsigned int` but you passed it `unsigned char`(http://stackoverflow.com/questions/27547377/format-specifier-for-unsigned-char) – Giorgi Moniava Dec 09 '15 at 11:54
  • 1
    Possible duplicate of [Why are these constructs (using ++) undefined behavior?](http://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior) – too honest for this site Dec 09 '15 at 12:00
  • People should be required to read the info page of the C-tag before asking. – too honest for this site Dec 09 '15 at 12:01
  • @hvd: It is UB by the standard. That's all to research for. – too honest for this site Dec 09 '15 at 12:02
  • Which "number of bytes" do you mean? There is no `sizeof`. – too honest for this site Dec 09 '15 at 12:03
  • @Olaf: take a guess. – Karoly Horvath Dec 09 '15 at 12:05
  • @hvd But you do usually get predictable repeatable results for this for a given environment. OP said "from the right", i.e. right-to-left. I didn't think about it too hard but it looked correct, sorry if I got that wrong. – Rup Dec 09 '15 at 12:07
  • @Rup: http://stackoverflow.com/questions/949433/why-are-these-constructs-using-undefined-behavior And no, the compiler might (and will) very well swap evaluatio e.g. to optimise. – too honest for this site Dec 09 '15 at 12:07
  • @Rup: "predictable repeatable results for this for a given environment" - with UB, anything is allowed, including that. That doesn't mean that you should rely on it. – Karoly Horvath Dec 09 '15 at 12:09
  • @KarolyHorvath Yes! As I said in my first comment. – Rup Dec 09 '15 at 12:10
  • @Rup: too violent. just another of those questions already linked in the [C info-page](http://stackoverflow.com/tags/c/info). – too honest for this site Dec 09 '15 at 12:12
  • You are asking two questions. Do not. Ask only one per posting. – too honest for this site Dec 09 '15 at 12:15
  • @Olaf, My question was specifically related to difference in printf("%x", a) and printf("%x", ~a). But I think I couldnt make that clear.... P.S: People make mistakes.... – Tattu Dec 09 '15 at 12:16
  • @Rup Ah, thanks, I misread the question. I'm sure it's still not just technically undefined, but I don't have a concrete test case to show that and don't think it's worth it trying to come up with one. :) –  Dec 09 '15 at 12:17

2 Answers2

2

printf("----> %x %x %x %x", ~a, a, ~a, ++a); actually invokes undefined behavior because you have a side effect on a and other expressions depending on the same lvalue. So anything can happen and it is hopeless to try and explain the output produced.

Assuming 32 bit ints in 2's complement representation, if you wrote

printf("----> %x %x %x %x", ~a, a, ~a, a + 1);

You would get different and less surprising output:

ffffff01 fe ffffff01 ff

Let me explain what is going on:

a = ~a;

a contains 1, is converted to an int with the same value, the ~ operator applied to 1 computes to -2, converting that back to unsigned char gives 254 or 0xfe.

The arguments to printf are then computed as follows:

  • ~a: 0xfe is converted to int and all bit are complemented, yielding 0xffffff01.

  • a is converted to int with the same value and printed as fe.

  • ~a again of course gives the same output.

  • a+1: a is converted to int before incrementing by one, result is 255, prints as ff.

The explanation for your surprising outputs is that a is first converted to int and then the computation is done on the int value.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
1

a = ~a; You have integer promotion on this line already, since the ~, like most operators in C, promotes the operand according to the rules of integer promotion.

The character containing value 1 gets integer promoted to an int containing the value 1, before the operation is done. Assuming 32 bit int, the result of ~a is a negative, two complement variable with hex value 0xFFFFFFFE.

You then show this result back into the unsigned char, it will truncate the result and only grab the raw binary value of the least significant byte, that is: 0xFE.

I also know that the sequence of operation inside printf is from the right.

No. The order of evaluation of function parameters in not specified by the standard. The compiler is free to evaluate them in any order it likes, and you cannot know or assume any particular order.

Even more problematic is that there is no sequence point between the evaluation of the different parameters. And since in your case you are using the same variable more than once, each access to the variable is unsequenced and your program invokes undefined behavior. Meaning that anything can happen: weird outputs, program crashes, memory corruption etc etc.

Furthermore, printf is a special case, being an obscure, variadic function. All such functions have particular rules for promotion of the arguments ("the default argument promotions"). So regardless of what promotions that happen or don't happen before you pass the result to printf, printf will ruin everything by applying its own integer promotion to the parameter.

So if you wish to toy around with promotion, printf is a very bad choice for displaying the result. Try using the sizeof operator instead. printf("%zu", sizeof(~a)); will for example print 4, because of integer promotion.

Lundin
  • 195,001
  • 40
  • 254
  • 396