文章目錄
- 一、賦值時帶限定符問題(qualifier)
- 二、賦值時符號與無符號類型問題
- 三、文字量、變數取地址的類型問題
一、賦值時帶限定符問題(qualifier)
修飾符包括 const, static, ...
挑戰你的極限,你看看哪些賦值編譯器會報錯/警告?
左實值型別 |
右實值型別 |
可否賦值 |
解釋 |
|
|
|
|
普通類型之間賦值 |
|
|
|
char |
const char |
是 |
|
const char |
任何異己char |
否 |
|
|
|
|
|
指標類型之間賦值 |
|
|
|
char * |
const char * |
否 |
|
char * |
char * const |
是 |
|
char * |
const char * const |
是 |
|
const char * |
char * |
是 |
|
const char * |
char * const |
是 |
|
const char * |
const char * const |
是 |
|
char ** |
char * const * |
否 |
|
char ** |
char * const * const |
否 |
|
char ** |
const char ** |
否 |
|
char ** |
const char * const * |
否 |
|
char ** |
const char * const * const |
否 |
|
char ** |
char ** const |
是 |
|
const char ** |
char ** |
否 |
|
const char ** |
char * const * |
否 |
|
const char ** |
char * const * const |
否 |
|
const char ** |
const char * const * |
否 |
|
const char ** |
const char * const * const |
否 |
|
const char ** |
char ** const |
否 |
|
const char ** |
const char ** const |
是 |
|
char * const * |
char ** |
是 |
|
char * const * |
const char ** |
否 |
|
char * const * |
char * const * const |
是 |
|
char * const * |
const char * const * |
否 |
|
char * const * |
const char * const * const |
否 |
|
char * const * |
const char ** const |
否 |
|
char * const * |
char ** const |
是 |
|
(const) char * (const) * const |
任何異己指標 |
否 |
|
如果沒有清楚,請查詢ISO C具體章節,仔細體味。
1. 對於普通類型賦值: 規則很簡單
2. 對於指標類型賦值:
補充:如果右邊指標指向的類型不帶限定符,左邊指標指向的類型可以多加修飾符,如:
const char * const * |
const char ** |
二、賦值時符號與無符號類型問題
三、文字量、變數取地址的類型問題
變數/常量取地址:
是一個const指標類型,此指標不允許再指向其他地址。
注意:變數和常量都是需要分配儲存空間的,只是其值是否唯讀這種限定的區別而已。
很簡單的測試:
#include <stdio.h>
int main()
{
int i=0;
int j=1;
&i=&j;
return 0;
}
編譯錯誤: 無效的左值
&i的類型應該為int * const
#include <stdio.h>
int main()
{
const int i=0;
++*(&i);
return 0;
}
編譯錯誤。
&i的類型應該是const int * const
文字量取地址:
一般來說,內建類型的文字量都是編譯時間直接計算出來,表現在彙編層級就是"立即數"(immi )。於是它們不存在地址的問題。這些文字量包括比如1, 1.23以及宏展開,它們是不佔用儲存空間。
於是,對上述文字量取地址是非法的. 即&操作符不允許應用到上述的文字量。你試試:
#include <stdio.h>
int main()
{
int * ptr = &0;
return 0;
}
編譯通不過:invalid lvalue in unary `&'
但是唯一可以取地址操作的文字量是:字串!
#include <stdio.h>
int main()
{
char * ptr = (char *)&("this is a string");
return 0;
}
OK, 編譯沒問題!
其中,
char * ptr = &("this is a string");
等價於
char * ptr = "this is a string";
C語言在語言層面在做了上述簡化的等價保證
字串文字量是占儲存空間的,它們一般分配到唯讀區,因此對它們取地址的類型應該是const char * const. 依照第一部分的總結,此地址可以賦給char *或者const char *
測試:
#include <stdio.h>
int main()
{
char * ptr = (char *)&("this is a string");
*ptr = 'r';
printf("%c", *ptr);
return 0;
}
編譯可以通過?!
沒什麼好奇怪的!因為編譯期是靜態類型檢查,ptr的靜態類型是char *,但是實際上它指向的是const char, 所以它騙過了編譯器。編譯器可夠愚蠢了:)
但是,罪犯會逍遙於法外嗎?不會
果不其然,運行時事發東窗了,運行時異常出錯!
像上面的錯誤,如果剛開始就寫成
const char * ptr = (char *)&("this is a string");
那麼,在編譯期就可以報錯!
同樣結果也出現在:
#include <stdio.h>
int main()
{
char * ptr = "this is a string";
*ptr = 'r';
printf("%c", *ptr);
return 0;
}
總結:
1. 明確搞清楚取地址後的文字量、常量、變數的類型,當將它們賦給其他指標時,此指標類型最好寫明確,以避免出現編譯器正確,運行時卻報錯的問題
2
本文中總結賦值時一些類型的問題,在函數參數傳遞中用到這些規則。請見http://www.cnblogs.com/chio/archive/2008/09/21/1295082.html