<div class="gmail_quote">On Thu, Apr 12, 2012 at 15:57, Rob Latham <span dir="ltr"><<a href="mailto:robl@mcs.anl.gov">robl@mcs.anl.gov</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div id=":p6">Is there some C magic I don't know about that will make the compiler<br>
properly handle '-sizeof(int)' ? The next time someone tries to "seek<br>
backwards by 5 integers" into a file, I don't want them running into<br>
this.</div></blockquote></div><br><div>So the magic is that unary - first performs the "integer promotions" before it starts working.</div><div><div><br></div><div>C99-n1256 section 6.5.3.3.3:<br><div><i><br></i></div>
<div><i>The result of the unary - operator is the negative of its (promoted) operand. The integer promotions are performed on the operand, and the result has the promoted type.</i></div></div></div><div><i><br></i></div><div>
Section 6.3.1.1</div><div><br></div><div><div><i>If an int can represent all values of the original type, the value is converted to an int; otherwise, it is converted to an unsigned int. These are called the integer promotions.^48 All other types are unchanged by the integer promotions.</i></div>
</div><div><div><i><br></i></div><div><i>[48] The integer promotions are applied only: as part of the usual arithmetic conversions, to certain argument expressions, to the operands of the unary +, -, and ~ operators, and to both operands of the shift operators, as specified by their respective subclauses.</i></div>
</div><div><br></div><div><br></div><div>So unary - first promotes all types smaller than int (whether signed or unsigned) to signed int, but it does not convert unsigned int (or any of the larger types). Since there are no further conversions, unary - is applied to an unsigned type, producing an unsigned result. The actual value is implementation defined, but most/all compilers on twos complement systems will insert a normal signed negation instruction (NEG on Intel). All this to say that when the argument to unary - is an unsigned type with rank >= to the rank of int, the result is also unsigned. If we cast it to any longer type, it is a large positive number instead of a negative number. If we cast it to a signed type of the same size, we "get lucky" and get the same thing as we would have gotten by casting to an unsigned type before applying unary -.</div>
<div><br></div><div>This on LP64 (Linux x86-64)</div><div>a.c:</div><div><div><font face="'courier new', monospace">#include <stdio.h></font></div><div><font face="'courier new', monospace">#define test(type) printf("sizeof((%s)4)=%zd\tsizeof(-(%s)4)=%zd\tvalue as long=%ld\n",#type,sizeof((type)4),#type,sizeof(-(type)4),(long)-(type)4)</font></div>
<div><font face="'courier new', monospace">int main(void)</font></div><div><font face="'courier new', monospace">{</font></div><div><font face="'courier new', monospace"> test(unsigned char);</font></div>
<div><font face="'courier new', monospace"> test(unsigned short);</font></div><div><font face="'courier new', monospace"> test(unsigned int);</font></div><div><font face="'courier new', monospace"> test(unsigned long);</font></div>
<div><font face="'courier new', monospace"> test(unsigned long long);</font></div><div><font face="'courier new', monospace"> return 0;</font></div><div><font face="'courier new', monospace">}</font></div>
</div><div><font face="'courier new', monospace"><br></font></div><div><div><font face="'courier new', monospace">$ gcc -Wall -Wextra b.c && ./a.out</font></div><div><font face="'courier new', monospace">sizeof((unsigned char)4)=1 sizeof(-(unsigned char)4)=4 value as long=-4</font></div>
<div><font face="'courier new', monospace">sizeof((unsigned short)4)=2 sizeof(-(unsigned short)4)=4 value as long=-4</font></div><div><font face="'courier new', monospace">sizeof((unsigned int)4)=4 sizeof(-(unsigned int)4)=4 value as long=4294967292</font></div>
<div><font face="'courier new', monospace">sizeof((unsigned long)4)=8 sizeof(-(unsigned long)4)=8 value as long=-4</font></div><div><font face="'courier new', monospace">sizeof((unsigned long long)4)=8 sizeof(-(unsigned long long)4)=8 value as long=-4</font></div>
</div><div><br></div><div>If you want consistent results across sizes, be sure that the argument to unary - is always signed.</div>