Below is a collection of tips/tricks/caveats for LP64 c coding,
full text is at http://www.cs.albany.edu/~mosh/Text/c-ref.txt.
Hope it helps, corrections welkome.
-- Panchi51<et>pacbell.net
LP64 Gotcha List
----------------
1. sizeof long array can overflow on lp64.
uchar n = sizeof( 50*sizeof(long)); // 200 bytes in ilp32, 400
bytes in lp64.
2. Use u U L l suffix on large const.
long l = 1 <<32; // 0 on ilp32,lp64
long l = 1L<<32; // 2^32 on lp64, 0 on ilp32.
Solaris: see /usr/include/sys/inttypes.h
INT64_C(5) => 5ll for ILP32, and 5l for LP64.
0x80000000L ulong in lp32, long in lp64.
3. Bit fields are converted to int and sign-extended (or uint if too
large) in expr.
struct { uint b:19, r:13 }x;
uint y = x.b<<13 // x.b first converted to int and sign extended!
uint y = (uint)x.b << 13; // ok.
4. Integer Arithmetic on ptr, ptr is trucated to int32.
char *p="x";
(int)p+1=='\0' // p is trunc to int32.
(uintptr_t)p+1=='\0' // ok.
5. Unprotyped func returning ptr is trucated to int32.
// int login(...); -- implicit C decl.
char *p = getenv("HOME"); // p is trucated to int32, crash.
6. Saving ptr in int, losses upper 4 bytes of ptr.
void *q;
int p = (int)q; // truncated to int32
7. Unions with long.
union {
long x;
int y; // on lp64, y gets lsb of x.
}
8. Print format specifier
char *p="x";
printf("p=0x%08x",p); // losses msb.
printf("p=%p", p); // ok.
long x=LONG_MAX;
printf("x=%d ",x); // truncated, wrong.
printf("x=%ld",x); // ok.
9. Casting *int into *long.
int *i;
long *p;
p+1; // p+=4 on ilp32
p+1; // p+=8 on lp64
p = (long*) i; // p misaligned pointing to *i and *(i+1).
i = ( int*) p; // i pointing to lsb of p.
10. Unsigned bit fields (default sign and alignment).
struct { b:12, int:0, d:5 } x; // b is unsigned in lp64, signed
in ilp32.
// :0 affects alignment in ilp32, no effect in lp64.
11. LP64 Perf Problems
Larger exe, need more TLB, cache, mem (wrt same src compiled as
ILP32).
Long div slow in lp64, eg. 1L/9.
Int Array indexes are sign-ext on every use, need more instruction
in LP64, eg. int i; a[i];
12. Expression sizing:
Example.
int x,y;
long z = x + y; // x+y done in 32bit, then assignment will resize
result for z.
Example.
ulong y = (1 <<32); // overflows in lp32 and lp64.
ulong y = (1L<<32); // overflows in lp32, ok 2^32 in lp64.
13. Promotions:
result = a op b;
// 1. type of tmp is of max of a and b.
// 2. tmp = a op b
// 3. promote tmp to type of result, ptmp.
// 4. result = ptmp;
Example.
long l=-1; uint i=1;
if( l > i ) printf("ilp32"); // -1 is promoted to uint32.
else printf("lp64"); // both promoted to signed 64.
if( l > (long)i ) // fix
...;
Example.
main(){ // k is -1 in LP32, 4294967295 in LP64
int i = -2;
unsigned int j = 1;
long k = i+j;
printf("int %d+ uint %ld= long k is %ld\n",i,j,k);
}
15. Prototype:
// #include <stdlib.h> missing.
int *i = malloc(sizeof(*i));
// Ok in lp32, Crash on lp64 because
// malloc will return 32bit int value because of missing
prototype.
}
////////////////////////////////////////////////////
Examples
cc +DA2.0W +w1 +M2 enquire.c # +w1 for warnings, +M2 for 64bits
long double=128 bits
# Sort LP64 warning by problem: make 2>&1 | grep LP64 | xsort 'warning:\s+\S+:' | align warn > lp64.log vim lp64.log :set isk+=46 " Make . part of tag, so file.c is a keyword for
tags"
emacs lp64.log
M-x compilation-minor-mode
M-x next-error ; if cant find files, set
; (setq compilation-search-path '("dir1" "dir2")) C-xC-e
/714: Function "malloc" called with no prototype or definition in
scope
/724: Initialization converts default int return type to pointer
/722:.*cast converts 32 bit constant to pointer
/725:.*cast converts 32 bit integer to pointer
/727:.*cast truncates pointer into 32 bit integer
/729:.*converts int* to long*
/732:.*different types treated as unsigned
/740:.*casting to a smaller size may truncate
/530:.*casting from loose to strict alignment
/720:.*Assignment may overflow
// Example
catt -n x.c
1 void main(){
2 int *x, *q, i;
3 long l=-1;
4 x = malloc(sizeof(int)*10);
5 (int*)i;
6 (int) &i;
7 (long*)&i;
8 i = l;
9 }
hp64> cc +DA2.0W +M2 +w1 -Aa x.c
/*
line 4: warning 714: Function "malloc" called with no prototype or
definition in scope.
line 4: warning 724: LP64 migration: Assignment converts default int
return type to pointer "x".
line 5: warning 725: LP64 migration: Cast converts 32 bit integer to
pointer.
line 6: warning 727: LP64 migration: Cast truncates pointer into 32
bit integer.
line 7: warning 530: LP64 migration: Casting from loose to strict
alignment: Resulting pointer may be misaligned.
line 7: warning 729: LP64 migration: Cast converts int* to long*.
line 8: warning 720: LP64 migration: Assignment may overflow integer
"i".
*/
/////////////////////////////////////////////////
A. Sizes
Ansi sizeof() is always unsigned, try:
if( 0-sizeof(int) > 0 ) printf("See: 0-sizeof(int) is
unsigned!\n");
ILP32: win32 hp11 solaris linux
ANSI C Integer Requirements, see C book. moshtag=ansi_int
sizeof(int) >= sizeof(short) >= 2.
sizeof(long) >=sizeof(int)
sizeof(long) >= 4.
LP64: hp11_64 solaris_64 (assume default for 64bit).
New: sizeof(long)==sizeof(void*)==8, rest unchanged.
P64: win64
New: sizeof(void*)==8, rest unchanged.
//////////////////////////////////////////////////////////
Linux64 moshtag=linux64
char = 8 bits, signed
short=16 int=32 long=64 float=32 double=64 bits
long double=128 bits
Type size_t is unsigned long
ALIGNMENTS
char=1 short=2 int=4 long=8 float=4 double=8 long double=16
char*=8 int*=8 func*=8
short: BA
int: DCBA
long: HGFEDCBA
Maximum long = 9223372036854775807 (= 2**63-1)
Minimum long = -9223372036854775808
Maximum unsigned short = 65535
Maximum unsigned int = 4294967295
Maximum unsigned long = 18446744073709551615
PROMOTIONS
unsigned short promotes to signed int
long+unsigned gives signed long
HP64 ALIGNMENTS
char=1 short=2 int=4 long=8 float=4 double=8 long double=16
char*=8 int*=8 func*=8
//////////////////////////////////////////////////////////