看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《leontsai (幻風)》之銘言: : 有沒有高手請教一下我的疑惑 : 感恩 : 這MACRO 最主要是要回傳This 指標的PRIVATE 資料 : 其中 : Record 為一指標 BBS_PROTOCOL * This : TYPE 為一結構 : Field 為結構TYPE 中一個 component : #define _CR(Record, TYPE, Field) \ : ((TYPE *) ( (CHAR8 *)(Record) - (CHAR8 *) &(((TYPE *) 0)->Field))) : 1.最不能理解的是 0 ((TYPE *) 0) 這結構0代表是神麼意思? : 2. &(((TYPE *) 0)->Field))) 轉型為 (CHAR8 *) ? 位址轉型為 指向 CHAR8 的指標 抱歉回了這麼久以前的文, 小弟最近在一個偶然的機會.... 又看到了這個三年前面試被問過的題目, 本想po文請教.... 沒想到板上已經有文章了, 那就回在同一個標題下面吧.... 憑印象記的macro, 加自己湊的範例, code不長直接貼吧@@" == #include <stdio.h> #include <stdlib.h> #define OFFSET(type, element) ( &(((type*)0)->element) ) typedef struct _TESTrec { int x, y; char str[10]; double z; int dummy[2]; } TEST; int main() { printf("sizeof(TEST) = 0x%08X\n", sizeof(TEST)); printf("offset of str = 0x%p\n", OFFSET(TEST, str)); printf("offset of z = 0x%p\n", OFFSET(TEST, z)); system("PAUSE"); return 0; } == 主要是OFFSET這個macro裡這段: ((type*)0)->element 以前老迷惑於"對0轉型成指標存取element為什麼不會access violation"?? 然後又取址, 或者像l大看到的組合了一堆奇怪的位址運算到底是算什麼?_? 剛剛憑印象生出上面的code以後, 大概有了如下的推論 OFFSET(TEST, str) 展開以後 ( &(((TEST*)0)->str) ) 如果把 0 (零) 假設當成TEST* O (大o) 來看好了.... 這段code可寫成 &(O->str), 如果O指到0x0010000.... 那麼O->str指0x00100008, O->z指0x00100018(有align) 接著如果O指到0x00000000呢??就跟macro一模一樣了.... 那麼O->str指0x00000008, O->z指0x00000018(有align) 所以OFFSET在上例算出0x00000008與0x00000018兩位址! 也就是說它只是拿來找element在type裡的offset而已Orz -- 藉這篇文悼念一下被&(type*)0->element嚇傻的日子-_-|| PS. 以上數值舉例是假設在sizeof(int)為32的環境下.... -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 220.132.174.98 ※ 編輯: VictorTom 來自: 220.132.174.98 (07/20 01:35)
loveme00835: V大 拍拍~ 07/20 01:47
saxontai:C Standard Library 有提供 offsetof marcro。 07/20 11:09
saxontai:#18xs7RbK 07/20 11:10
VictorTom:感謝樓上s大的文章....<(_ _)> 07/20 11:18
VictorTom:也推一下 #18xm_p1G g大寫的解釋....:) 07/20 11:28
godman362:我有疑問,關於g大的return &(ptr->c) 為什麼不會有問題 07/20 14:37
godman362:ptr不是擺明指向NULL了嗎?這樣return &(ptr->c)的位址 07/20 14:37
godman362:不會有問題產生嗎...? 07/20 14:38
godman362:呃抱歉,我沒注意到V大也有解釋 07/20 14:39
tinlans:這個 code 之所以能動作是因為標準賦予 & 了特殊的規則。 07/20 15:36
tinlans:所以把那一行拆成兩行寫雖然看似等價,但拆開會死。 07/20 15:36
tinlans:不過,好像也沒有拆開寫的方法就是了... 07/20 15:39
tinlans:同樣的 &(((struct T *)0)[1]) 也是有保證不會真的去做 07/20 15:43
tinlans:dereference,會直接代換成加法運算。 07/20 15:43
VictorTom:感謝t大的說明....<(_ _)> 07/20 16:59