2017年4月7日 星期五

c 語言中的 0x7fffffff 和 0xffff0000 是什麼 type?

在 c 程式碼上的一個數字, 他們是什麼型別呢? int, unsigned int, long int ... 你會不會有類似的疑惑呢? 而不知道他們是什麼型別有什麼要緊的呢? 有經驗的程式員馬上就聯想到會不會有 overflow 的問題。

5+253 如果 5 是 unsigned char, 253 是 unsigned char, 那加起來不就超過 char 的大小了嗎? 但是
cout << 5+300 << endl;
可以正常印出 258, 而不是被截掉的數值。

那這兩個數字 0x7fffffff 和 0xffff0000 是什麼 type 呢?

為什麼 0x7fffffff 不是 unsigned int?《linux c 編程 一站式學習》有答案, 我想驗證看看是不是真的, 其實應該讀 c spec, 但你知道的 ...

該怎麼驗證呢? 使用 c++ rtti, 以下程式碼使用 c++ rtti 來得到 type。

c++filt -t 可以把神秘的字母轉成看得懂的 type。

a.cpp
 1 #include <typeinfo>
 1 #include <typeinfo>
 2 #include <iostream>
 3 using namespace std;
 4 
 5 #include <sys/types.h>
 6 #include <sys/stat.h>
 7 #include <fcntl.h>
 8 #include <unistd.h>
 9 #include <sys/mman.h>
10 
11 
12 int main(int argc, char *argv[])
13 {
14   cout << "0x7fffffff type:" << typeid(0x7fffffff).name() << endl;
15   cout << "0xffff0000 type: " << typeid(0xffff0000).name() << endl;
16   cout << "off_t type: " << typeid(off_t).name() << endl;
17   return 0;
18 }

51 descent@debian64:tmp$ ./a.out |c++filt 
52 0x7fffffff type:i
53 0xffff0000 type: j
54 off_t type: l


71 descent@debian64:tmp$ ./a.out |c++filt -t
72 0x7fffffff type:int
73 0xffff0000 type: unsigned int
74 off_t type: long


再來是一個很特別的數字, -2147483648。
測試環境是:
x86 32bit/linux
gcc 5.4.0
int: 32bit
longlong: 64bit

-2147483648 可以用 int 大小 (32bit) 裝下, 0x80000000 是其 16 進位表達式。
2147483648 卻要用 long long 大小 (64bit) 才能裝下, 0x0000000080000000 是其 16 進位表達式。

int.cpp
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <typeinfo>
 4
 5 using namespace std;
 6
 7
 8 int main(int argc, char *argv[])
 9 {
10   int i = -2147483648;
11   cout <<  typeid(-2147483648).name() << endl;
12   printf("%d\n", -2147483648);
13 }

descent@debian64:ctrl_proc$ g++ -m32 -Wall -std=c++11 int.cpp -o int
int.cpp: In function ‘int main(int, char**)’:
int.cpp:12:29: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=]
   printf("%d\n", -2147483648);
                             ^
int.cpp:10:7: warning: unused variable ‘i’ [-Wunused-variable]
   int i = -2147483648;
       ^
descent@debian64:ctrl_proc$ ./int |c++filt -t
long long
-2147483648

-2147483648 type 是 long long, 而不是 int, 雖然 int 裝的下 -2147483648, 怎麼回事, 從 AST 來看這個 printf("%d\n", -2147483648); 運算式。

main |int |func |global
           |
       func_body
           |
         printf
         __|___
         |    |
        %d\n  -
              |
          2147483648

-2147483648 被分成 -, 2147483648, 而 2147483648 是 long long type, 做了 - 運算後, 依然是 long long, 所以 -2147483648 是 long long, 也就是 0xffffffff80000000, 而 %d 預期是 int type, 所以編譯器便發出 warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘long long int’ [-Wformat=] 警告。

有趣的是 int.cpp L10, int i = -2147483648; 卻不會發警告, int i 是可以存進 -2147483648, 真奇怪, -2147483648 的 type 是 long long, 所以會有被截掉的可能, 但是由於 -2147483648 可以裝進 int, 所以不用擔心會被截掉。

linux c 編程 一站式學習》作者很謹慎, 沒亂唬爛我。

c++ 是不是好用呢? 有一些高階語言的特性與低階語言的執行速度, 它是很了不起的語言。

ref:
Strange output of std::typeid::name()

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。