最近在把老人寫的code 在x86_64 上做測試
才深刻體會原來寫一個好程式 要注意 data type 的使用
在32bit 機器上
#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
int pp = (int)p;
return 0;
}
但這太麻煩了, stdint.h 內定義了 intptr_t 這個type
當你需要把pointer 轉型成 integer 的時候 你不確定是32 or 64bit
就可以使用intptr_t
#include <stdio.h>
#include <stdint.h>
int main()
{
int i = 10;
int *p = &i;
intptr_t pp = (intptr_t)p;
return 0;
}
所以 下面這三個打印數值是相同的
#include <stdio.h>
#include <stdint.h>
int main()
{
int i = 10;
int *p = &i;
intptr_t pp = (intptr_t)p;
printf("%p\n", p);
printf("%lx\n", pp);
printf("%p\n", &i);
return 0;
}
在32bit 機器上
#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
int pp = (int)p;
return 0;
}
gcc 不會warning
但同樣程式在64bit 機器上跑
cast.c:7:20: warning: cast from pointer to integer of different size [-Wpointer-to-int-cast]
int pp = (int)p;
這是warning 理論上你可以不用管他
但是這很危險 可能會產生出很多莫名其妙的bug ~~
所以編譯程式最好加上 -Werror
把warning 都當成error 處理
迫使你寫的程式沒有額外的風險
回到正題
在64 bit上要解決這個warning or error
要改成
#include <stdio.h>
int main()
{
int i = 10;
int *p = &i;
long pp = (long)p;
return 0;
}
為什麼? 因為32bit 跟64bit 機器上pointer 長度不同啊
一個是32 bit 一個是64 bit
所以把64bit 資料強迫轉型成32 bit integer 當然要警告你 可能會lost data
當然你可以下面這種方式來解決
if machine32
int pp = (int)p;
elif machine64
long pp = (long)p;
endif
但這太麻煩了, stdint.h 內定義了 intptr_t 這個type
當你需要把pointer 轉型成 integer 的時候 你不確定是32 or 64bit
就可以使用intptr_t
#include <stdio.h>
#include <stdint.h>
int main()
{
int i = 10;
int *p = &i;
intptr_t pp = (intptr_t)p;
return 0;
}
所以 下面這三個打印數值是相同的
#include <stdio.h>
#include <stdint.h>
int main()
{
int i = 10;
int *p = &i;
intptr_t pp = (intptr_t)p;
printf("%p\n", p);
printf("%lx\n", pp);
printf("%p\n", &i);
return 0;
}
來看看stdint.h 怎樣定義intptr_t
/* Types for `void *' pointers. */
#if __WORDSIZE == 64
# ifndef __intptr_t_defined
typedef long int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned long int uintptr_t;
#else
# ifndef __intptr_t_defined
typedef int intptr_t;
# define __intptr_t_defined
# endif
typedef unsigned int uintptr_t;
#endif
偵測到是64bit
intptr_t 就是long int ( 64位元的long int 是64bit, 但32位元的long int是32bit)
否則就是 int ( 64位元的 int 是32bit, 32位元的int 也是32bit)
================================
同樣的, 關於portability 還有幾點需要介紹
那就是primitive data type
32 64
char 1 1
short 2 2
int 4 4
long 4 8
long long 8 8
pointer 4 8
可以注意到 long, and pointer type 是有差異的
所以long 必不portable
所以stdint.h 內也定義了
35 #ifndef __int8_t_defined
36 # define __int8_t_defined
37 typedef signed char int8_t;
38 typedef short int int16_t;
39 typedef int int32_t;
40 # if __WORDSIZE == 64
41 typedef long int int64_t;
42 # else
43 __extension__
44 typedef long long int int64_t;
45 # endif
46 #endif
47
如果你明確要使用64位元的整數 請使用int64_t
可以看到int64_t 在64bit machine 是long int
而32bit machine 要用long long int
================= size_t =================
看看下面這個小程式
1 #include <stdio.h>
2 #include <string.h>
3
4 void main()
5 {
6 int i = -1;
7 if (i > strlen ("hello"))
8 printf("hello\n");
9 }
==================ptrdiff_t ================
同樣的 用來表示pointer 之間的difference
但是是signed integer
64bit machine => long
32bit machine => int
================================
同樣的, 關於portability 還有幾點需要介紹
那就是primitive data type
32 64
char 1 1
short 2 2
int 4 4
long 4 8
long long 8 8
pointer 4 8
可以注意到 long, and pointer type 是有差異的
所以long 必不portable
所以stdint.h 內也定義了
35 #ifndef __int8_t_defined
36 # define __int8_t_defined
37 typedef signed char int8_t;
38 typedef short int int16_t;
39 typedef int int32_t;
40 # if __WORDSIZE == 64
41 typedef long int int64_t;
42 # else
43 __extension__
44 typedef long long int int64_t;
45 # endif
46 #endif
47
如果你明確要使用64位元的整數 請使用int64_t
可以看到int64_t 在64bit machine 是long int
而32bit machine 要用long long int
================= size_t =================
看看下面這個小程式
1 #include <stdio.h>
2 #include <string.h>
3
4 void main()
5 {
6 int i = -1;
7 if (i > strlen ("hello"))
8 printf("hello\n");
9 }
-1 > 5 ?
yes, 確實會印出hello
這裡的問題是 i 是signed , 用來跟strlen 傳回的size_t (unsigned ) 做比較
會把signed i 轉unsigned
(unsigned) (-1) 會大於 5
再回來review code
當我們要知道元素大小的時候 我們可以確定至少是0以上
所以應該要用unsigned 來表示
但我們卻常常為了方便而使用int
所以size_t 定義成unsigned integer
而且是平台相關的
在64bit machine size_t 是unsigned long
但在32bit machine size_t 是unsigned int
==================ptrdiff_t ================
同樣的 用來表示pointer 之間的difference
但是是signed integer
64bit machine => long
32bit machine => int
沒有留言:
張貼留言