[mpich-discuss] robust-ifying MPI_File_seek and negative offsets

Jed Brown jedbrown at mcs.anl.gov
Fri Apr 13 07:58:14 CDT 2012


On Thu, Apr 12, 2012 at 15:57, Rob Latham <robl at mcs.anl.gov> wrote:

> Is there some C magic I don't know about that will make the compiler
> properly handle '-sizeof(int)' ?  The next time someone tries to "seek
> backwards by 5 integers" into a file, I don't want them running into
> this.
>

So the magic is that unary - first performs the "integer promotions" before
it starts working.

C99-n1256 section 6.5.3.3.3:
*
*
*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.*
*
*
Section 6.3.1.1

*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.*
*
*
*[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.*


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 -.

This on LP64 (Linux x86-64)
a.c:
#include <stdio.h>
#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)
int main(void)
{
  test(unsigned char);
  test(unsigned short);
  test(unsigned int);
  test(unsigned long);
  test(unsigned long long);
  return 0;
}

$ gcc -Wall -Wextra b.c && ./a.out
sizeof((unsigned char)4)=1      sizeof(-(unsigned char)4)=4     value as
long=-4
sizeof((unsigned short)4)=2     sizeof(-(unsigned short)4)=4    value as
long=-4
sizeof((unsigned int)4)=4       sizeof(-(unsigned int)4)=4      value as
long=4294967292
sizeof((unsigned long)4)=8      sizeof(-(unsigned long)4)=8     value as
long=-4
sizeof((unsigned long long)4)=8 sizeof(-(unsigned long long)4)=8
 value as long=-4

If you want consistent results across sizes, be sure that the argument to
unary - is always signed.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.mcs.anl.gov/pipermail/mpich-discuss/attachments/20120413/088b800c/attachment-0001.htm>


More information about the mpich-discuss mailing list