看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《ericerix (我的帥,在於臉)》之銘言: : int main(){ : int a[5] = {1, 2, 3, 4, 5}; : int *p = (int *)(&a + 1); : printf("%d, %d",*(a+1), (*p-1)); : return 0; : } 在說明以前, 先定義以下巨集 (macro) 來讓編譯器告訴我們敘述的 型別是什麼: #define TYPENAME_OF(var) _Generic((var), \ int(*)[5]: "int(*)[5]", \ int* : "int*", \ int : "int", \ default : "unknown" \ ) 然後我們就可以試著印出以下幾個敘述的型別: printf("TYPENAME_OF(&a): %s\n", TYPENAME_OF(&a)); printf("TYPENAME_OF(&a + 1): %s\n", TYPENAME_OF(&a + 1)); printf("TYPENAME_OF(p): %s\n", TYPENAME_OF(p)); // output: // TYPENAME_OF(&a): int(*)[5] // TYPENAME_OF(&a + 1): int(*)[5] // TYPENAME_OF(p): int* 從這可以看到其實 (&a + 1) 的型別和 p 是不相容的, 所以在不加 轉型時編譯器會報 warning. 不是說不能做這樣的轉型, 但你要清 楚知道對陣列或是變數 var 來說, 能夠取值的位址範圍落在 [&var, &var + 1) 之間 (6.5.6/9), 除此之外都是 undefined be- havior. printf("valid address range: [%p, %p)\n", &a, &a + 1); printf("a + 1: %p\n", a + 1); printf("p : %p\n", p); // (possible) output: // valid address range: [0x7fffffb2ede0, 0x7fffffb2edf4) // a + 1: 0x7fffffb2ede4 // p : 0x7fffffb2edf4 因為 p 指到界外, 所以原本程式裡的 *p 是不合法的; 如果改成 p - 1 雖然指標值剛好和最後一個元素的位址相同, 但因為 p 的語 意已經和 (&a + 1) 不一樣 (one past the last element), 原則 上拿 p 往前減再取值依然是 undefined behavior. 不管對哪個陣 列而言, p 都是外部指標, 不能透過外部指標直接或間接存取陣列 元素. 如果想避免 undefined behavior, 那記得當你想存取 int 元素時, 從任意 int 元素的位址 (內部指標) 開始做計算: int *p = a + (sizeof a / sizeof a[0]); printf("*(p - 1): %d\n", *(p - 1)); 指向 one past the last element 的指標雖然無法用來取值, 但它 仍屬於陣列的內部指標. - References ISO/IEC 9899:202x (E) (N2596) http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2596.pdf Pointers are more abstract than you might expect in C https://pvs-studio.com/en/blog/posts/cpp/0576/ -- [P1389R1] Standing Document for SG20: Guidelines for Teaching C++ to Beginners https://wg21.link/p1389r1 SG20 Education and Recommended Videos for Teaching C++ https://www.cjdb.com.au/sg20-and-videos -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 118.233.156.253 (臺灣) ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1626976246.A.CB6.html
ericerix: 太詳細了,謝謝大大替我解答。那個巨集的寫法我沒讀到過 07/23 09:49
ericerix: ,請問有關鍵字能夠查詢嗎? 07/23 09:49
_Generic (generic selection) 是 C11 時加入的特性唷, 用來根 據型別選取特定的敘述 https://en.cppreference.com/w/c/language/generic
LPH66: C11 的新東西, 讓編譯器用式子的形態選式子執行 07/23 09:56
Jockey66666: 又偷學一招,棒 07/23 10:48
ericerix: 謝謝你! 07/23 11:22
sarafciel: 推 07/23 11:39
※ 編輯: poyenc (118.233.156.253 臺灣), 07/23/2021 15:27:36
F04E: 板主怎麼都沒m 07/23 15:40
DLHZ: 推用心 07/26 19:05