乙個關於空指標的思考

2022-02-18 07:53:07 字數 3708 閱讀 2539

最近在看**時發現乙個用於求結構體成員偏移量的方式

#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,寫驗證**如下:

int

main()

反彙編後的結果為:

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,寫驗證**如下:

int

main()

反彙編後的結果為:

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...