最近在看**時發現乙個用於求結構體成員偏移量的方式
#define nbb_offsetof(struct, field) (nbb_buf_size)((nbb_byte *)(&((struct *)0)->field) - (nbb_byte *)0)
奇怪的是對(struct *)0)->field的引用怎麼不會出現錯誤呢?
於是寫了如下**進行簡單的求證
#include #include#pragma pack(1)typedef
struct
student;
intmain()
其中int x= (char *)&((student *)0)->age - (char *)0這一行**用於求age在結構體中的偏移量(結果是3),對main函式反彙編後的結果如下:
08048424:8048424: 8d 4c 24
04 lea 0x4(%esp),%ecx
8048428: 83 e4 f0 and $0xfffffff0,%esp
804842b: ff
71 fc pushl -0x4(%ecx)
804842e:
55 push %ebp
804842f:
89 e5 mov %esp,%ebp
8048431: 51 push %ecx
8048432: 83 ec 24 sub $0x24,%esp #分配空間
8048435: c7 45 f8 03
0000
00 movl $0x3,-0x8(%ebp) #將0x3放入棧
804843c: 8b
45 f8 mov -0x8(%ebp),%eax
804843f:
8944
2404 mov %eax,0x4(%esp)
8048443: c7 04
2420
8504
08 movl $0x8048520,(%esp)
804844a: e8
05 ff ff ff call 8048354
804844f: b8
0000
0000 mov $0x0,%eax
8048454: 83 c4 24 add $0x24,%esp
8048457: 59 pop %ecx
8048458: 5d pop %ebp
8048459: 8d 61 fc lea -0x4(%ecx),%esp
804845c: c3 ret
從上述可以看出,在為printf函式分配空間後直接計算出了結果($0x3),並將該值放入棧中,其中並沒有對0位址進行任何訪問
在對空指標錯誤發生的場景進行思考後,總結出了以下場景:
1:對空指標進行賦值,即寫操作,如int *p =null;*p=6;
2:對空指標進行引用,即讀操作,如int *p = null;int a = *p;
對場景1,寫驗證**如下:
intmain()
反彙編後的結果為:
080483e4
:80483e4: 8d 4c
2404 lea 0x4(%esp),%ecx
80483e8:
83 e4 f0 and $0xfffffff0,%esp
80483eb: ff
71 fc pushl -0x4(%ecx)
80483ee:
55 push %ebp
80483ef:
89 e5 mov %esp,%ebp
80483f1:
51 push %ecx
80483f2:
83 ec 10 sub $0x10,%esp
80483f5: c7
45 f8 00
0000
00 movl $0x0,-0x8(%ebp) #取0位址
80483fc: 8b
45 f8 mov -0x8(%ebp),%eax
80483ff: c7
0006
0000
00 movl $0x6,(%eax) #將0x0位址內容設定為0x6,該處會段錯誤
8048405: b8 00
0000
00 mov $0x0,%eax
804840a:
83 c4 10 add $0x10,%esp
804840d:
59 pop %ecx
804840e: 5d pop %ebp
804840f: 8d
61 fc lea -0x4(%ecx),%esp
8048412: c3 ret
對場景2,寫驗證**如下:
intmain()
反彙編後的結果為:
080483e4 :80483e4: 8d 4c
2404 lea 0x4(%esp),%ecx
80483e8:
83 e4 f0 and $0xfffffff0,%esp
80483eb: ff
71 fc pushl -0x4(%ecx)
80483ee:
55 push %ebp
80483ef:
89 e5 mov %esp,%ebp
80483f1:
51 push %ecx
80483f2:
83 ec 10 sub $0x10,%esp
80483f5: c7
45 f4 00
0000
00 movl $0x0,-0xc(%ebp) #對p賦值0x0
80483fc: 8b
45 f4 mov -0xc(%ebp),%eax
80483ff: 8b
00 mov (%eax),%eax #對0位址取值 ,此處會導致段錯誤
8048401: 89
45 f8 mov %eax,-0x8(%ebp) #*p賦值給a
8048404: b8 00
0000
00 mov $0x0,%eax
8048409: 83 c4 10 add $0x10,%esp
804840c:
59 pop %ecx
804840d: 5d pop %ebp
804840e: 8d
61 fc lea -0x4(%ecx),%esp
8048411: c3 ret
得出的總結如下:
導致空指標段錯誤的原因是對空指標位址進行了讀或寫操作(printf乙個空指標其實也是對空指標進行了讀操作,然後將內容寫到顯示卡對應的記憶體)。
(nbb_byte *)(&((struct *)0)->field並沒有對0位址進行讀或寫操作,該表示式中的0更應該看做是乙個虛擬位址,代表了結構體的首位址,這樣可以方便地計算出結構體成員的偏移量,因此 (nbb_buf_size)((nbb_byte *)(&((struct *)0)->field) - (nbb_byte *)0)可以簡化為(nbb_buf_size)((nbb_byte *)(&((struct *)0)->field))
如有不正確的地方,歡迎**!
乙個關於127 1的思考
最近在學習c c 的過程中遇到了乙個有乙個問題,便借助本次機會和大家分享一下,也作為在csdn上的乙個開端。俗話說興趣是人們最好的導師,我欲對這門行業有著更加真實的認識,願計算機技術能引領我前進。對於這次這個問題,問題的描述是這個樣子的 當我們定義了乙個char型別的變數,將其賦初值為 0,那麼對其...
關於AI的乙個思考
人工智慧,顧名思義,人工 智慧型,人工好理解,即人力所能及的。但是 智慧型 一直以來備受爭議。人唯一了解的智慧型是人本身的智慧型,這是普遍認同的觀點。但是我們對自身智慧型的理解都非常有限,對構 的智慧型的必要元素也了解有限,所以產生的人工智慧也存在侷限性。就像是支援人工智慧底層的演算法,可能工程師只...
C 刪除空指標的乙個坑
最近使用了專案公共庫中看起來很穩定的乙個訊息佇列類 前同事留下的 起初用得還挺好。後來程式中突然出現了記憶體暴漲的情況,最後定位下來是這個類的問題。隨後花了一些時間定位出現問題的 其實在debug時都沒有找到問題 真正找到問題是憑著感覺在一堆 裡揪出了這樣一句話 delete void lparam...