電子產(chǎn)業(yè)一站式賦能平臺(tái)

PCB聯(lián)盟網(wǎng)

搜索
查看: 64|回復(fù): 0
收起左側(cè)

C語(yǔ)言為什么不檢查數(shù)組下標(biāo)

[復(fù)制鏈接]

485

主題

485

帖子

1623

積分

三級(jí)會(huì)員

Rank: 3Rank: 3

積分
1623
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2022-5-24 08:30:00 | 只看該作者 |只看大圖 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
引言
- `9 I6 A* ^# y$ P% x4 \+ ~最近在查一個(gè)bug,查到最后發(fā)現(xiàn)是數(shù)組越界導(dǎo)致的。數(shù)組只有30個(gè)字節(jié),代碼卻向這個(gè)數(shù)組填充了35個(gè)數(shù)據(jù),這個(gè)bug還是偶現(xiàn)的,查到它確實(shí)廢了一番功夫。我就突然想到:C語(yǔ)言為什么不檢查數(shù)組下標(biāo)呢???先來(lái)個(gè)demo驗(yàn)證下
! e5 M$ F) Q4 t0 W
  • #include#include# x# x# ~- m% w3 i  E. s8 w. A/ t; A
    int main(){    int data[5]={0};    for(int i=0;i8;++i)    {        printf("%d ",data);    }    printf("% H4 v- U2 p, I5 O3 ^
    ");
    / ]# D9 n+ {4 I' V* N! @    return 0;}結(jié)果顯示,C語(yǔ)言還真的不檢查數(shù)組的下標(biāo)。不僅沒(méi)有報(bào)錯(cuò),而且運(yùn)行正常4 \4 _$ T9 b$ M% m! _- u5 ?* Y8 E
    3 a4 _  ~& r" V9 j  i
    思考, p& A  A5 A+ a8 w6 a/ `* q
    這就讓我陷入了思考,C語(yǔ)言為什么不檢查下標(biāo)呢?想上文這么簡(jiǎn)單的,data數(shù)據(jù)組就5個(gè)數(shù)據(jù),編譯器是知道的,為什么是訪問(wèn)第8個(gè)數(shù)據(jù)時(shí),編譯器來(lái)個(gè)報(bào)錯(cuò)也沒(méi)有呢?我想到了之前的文章《指針與數(shù)組》中有如下示例代碼:
    % D. e- b: U6 o5 h4 E
  • void main(){    int data[4] = {0, 1, 2, 3};    int *p;    p = data +2;    printf("p[-1] is %d+ T# x8 C, H! g3 f+ N
    ",p[-1]);    printf("*(p-1) is %d
    . J$ P0 ?! q( y2 x. S",*(p-1));}運(yùn)行結(jié)果如下
    3 f* z, J" r: {  ~3 \; _8 V8 G ) Q! ~( p9 o1 n- k% U( X3 Z$ _" @
    不僅可以編譯通過(guò),還能正確的輸出結(jié)果為1。這表明,C的下標(biāo)引用和間接訪問(wèn)表達(dá)式是一樣的。這讓我突然意識(shí)到,數(shù)組的這些特性,如數(shù)組名本質(zhì)上是一個(gè)常量指針(不懂的同學(xué)看之前的推文《指針與數(shù)組》)C語(yǔ)言很難檢查下標(biāo)合法性的。如果C語(yǔ)言檢查數(shù)組是否越界,因?yàn)楫?dāng)數(shù)組出現(xiàn)在表達(dá)式中的時(shí)候,它會(huì)立刻被解讀成指針。此外,使用其他的指針變量也可以指向數(shù)組的任意元素,并且這個(gè)指針可以隨意進(jìn)行加減運(yùn)算。引用數(shù)組元素的時(shí)候,雖然你可以寫(xiě)成a,但是它只不過(guò)是*(a+i)的一種表達(dá),C語(yǔ)言本身的語(yǔ)法是無(wú)法檢查的,只能通過(guò)編譯器檢查。那么編譯器將加入額外的代碼用于檢測(cè)數(shù)組是否越界,C的下標(biāo)檢查所涉及的開(kāi)銷比你開(kāi)始想象的要多。編譯器必須在程序中插入指令,證實(shí)下標(biāo)的結(jié)果所引用的元素和指針表達(dá)式所指向的元素屬于同一個(gè)數(shù)組,可能僅僅是個(gè)小功能,生成的程序的數(shù)組檢查占有大量的代碼空間,這必將影響程序的運(yùn)行效率。這也讓我意識(shí)到一個(gè)事情:數(shù)組的標(biāo)識(shí)符(也就是數(shù)組名),它只包含并沒(méi)有包含數(shù)組的長(zhǎng)度的信息,它只是個(gè)地址信息,也就是上面說(shuō)的數(shù)組名本質(zhì)上是個(gè)常量指針。讀到這里,請(qǐng)你想一下,C語(yǔ)言有提供數(shù)組長(zhǎng)度的底層函數(shù)嗎???答案是否定的,一般情況下,我們獲取一個(gè)數(shù)組的長(zhǎng)度,我們可以獲取數(shù)組所占的內(nèi)存大小,然后除以單個(gè)元素的內(nèi)存大小計(jì)算數(shù)組長(zhǎng)度。
  • int a[8];printf("%d",sizeof(a)/sizeof(a[0]));2 l6 a4 h3 i( t' X4 L
    為什么不修復(fù)“漏洞”, N& a% m% R; F7 u+ j
    既然我們發(fā)現(xiàn)了上述問(wèn)題,那么那些C語(yǔ)言的大神為什么不修復(fù)這個(gè)“漏洞”呢?其他編程語(yǔ)言會(huì)吸取“教訓(xùn)”嗎?學(xué)過(guò)JAVA的同學(xué)可以看下面代碼
    2 I8 k7 z) N; n# G& n  s* h
  • int [][] array = {{1,2,3},{1,4}};System.out.println(array[1][2]);這也是一個(gè)數(shù)組越界訪問(wèn)的例子,但是JAVA的控制臺(tái)會(huì)打印如下信息Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 2
    $ p9 }& P( N! A* N( jat demo.Array.main(Array.java:31)
    " `5 a6 D% p! i0 C" K會(huì)明確告訴你數(shù)組下標(biāo)越界了,是的,高級(jí)語(yǔ)言JAVA是支持的。那么我們就來(lái)講講C語(yǔ)言的設(shè)計(jì)目標(biāo):提供一種能以簡(jiǎn)易的方式編譯、處理低級(jí)存儲(chǔ)器、僅產(chǎn)生少量的機(jī)器碼以及不需要任何運(yùn)行環(huán)境支持便能運(yùn)行的編程語(yǔ)言。如果C語(yǔ)言加入了類似下標(biāo)檢查,實(shí)現(xiàn)一個(gè)簡(jiǎn)單的數(shù)組數(shù)據(jù)寫(xiě)入,需要大量指令檢查下標(biāo)是否正確,那么還符合C語(yǔ)言設(shè)計(jì)目標(biāo)嗎?如果C語(yǔ)言有大量的這樣設(shè)計(jì),操作系統(tǒng)內(nèi)核還會(huì)使用C語(yǔ)言編寫(xiě)嗎?單片機(jī)等實(shí)時(shí)系統(tǒng)還會(huì)使用C語(yǔ)言嗎?所以C語(yǔ)言給了程序員更大空間,C語(yǔ)言執(zhí)行效率高,可以直接訪問(wèn)硬件,具有非常好的可移植性,所以世界上絕大部分的操作系統(tǒng)內(nèi)核都是用C語(yǔ)言編寫(xiě)的。那么問(wèn)題來(lái)了,JAVA都檢查了數(shù)組下標(biāo),C語(yǔ)言難道一點(diǎn)進(jìn)步也沒(méi)有嗎?其實(shí)也不然,微軟在這一方面也做了貢獻(xiàn)。在早期的CRT函數(shù)中也不對(duì)字符串指針或數(shù)組進(jìn)行越界檢查,都是要求程序員確?臻g足夠,因此也才也才有了在VS2005之后微軟提供的安全的CRT函數(shù)版本。(CRT函數(shù)不是本文的重點(diǎn),不懂的同學(xué)請(qǐng)面向百度編程)。
    - v4 m  W7 D3 m: R總結(jié)
    4 e4 z7 ~7 Q2 |6 rC語(yǔ)言為什么不檢查數(shù)組下標(biāo)???答案一個(gè)字:
    " h& Q$ x; y4 z, y' n+ F* W8 _$ T( W- r& |' R& m
    END2 B7 }& V% a/ c" a0 @6 B9 U

    1 X: w; w9 J. S* N& g. y7 E # s4 f& Z) C1 l- X
    ?STM32 IIC詳解5 _( ~. U& m! y* L: J; N
    ?VScode 調(diào)試C語(yǔ)言 必讀0 t% E8 G* G, R0 m7 [* W  ]: F& Q
    ?單片機(jī)中volatile的應(yīng)用! U* H9 |) P, r9 `
    ?聯(lián)合體在單片機(jī)編程中的應(yīng)用  必讀# k4 t, N" m5 R0 M1 Y4 R
    ?STM32串口開(kāi)發(fā)之環(huán)形緩沖區(qū)
  • 發(fā)表回復(fù)

    本版積分規(guī)則


    聯(lián)系客服 關(guān)注微信 下載APP 返回頂部 返回列表