乙個由sizeof引出的有意思的問題

2022-02-11 00:02:35 字數 1971 閱讀 7761

前段時間在乙個論壇上看到了乙個帖子,lz發了乙個**,如下。注意,sizeof語句後面沒有加分號。

#include 

<

stdio.h

>

intmain()

這個**實在太簡單了,我想大家學c/c++時都使用過這個**,我們都會這樣去看各種基本資料型別占用了幾個位元組的儲存空間,但是這個敲錯的**卻出現了乙個很詭異的問題:儘管sizeof一句後面忘了加分號,但是使用vc6編譯這個**卻是零錯誤零警告,只是執行時沒有任何輸出,這是怎麼回事呢?

我花了乙個多小時的時間,腦袋才終於轉過彎來。首先我們要明確一點,儘管我們通常都是用sizeof(a)這種形式使用它,但是sizeof是操作符,不是函式,也就是說sizeof a這種呼叫是完全正確的,就像++、--以及new這些操作符一樣,括號不是必須的,而且c語言對空格之類的字元並沒有什麼太嚴格的限制,所以"sizeof(long double)"和"printf("%d\n",a);"這兩句被vc6編譯器認為是同一句,相當於sizeof(long double)printf("%d\n",a);這一句的意思已經很明顯了,是先對printf()函式的返回值進行強制型別轉換,稱為long double型別,然後將long double型別所佔的位元組數賦值給變數a。

所以printf()函式是不會被執行的,我們只是需要對它的返回型別進行一次轉換而已,它的返回型別是int,從stdio.h裡的函式原型就能知道,沒必要呼叫它!如果我們在printf()函式下面再加一句同樣的printf語句,就可以看到這次成功地輸出了a的值是8。

從上面的分析來看,vc6能成功地編譯這個程式是正確的,雖然不小心漏掉了乙個分號,但是依舊是符合c語言規定的,但是如果到gcc或者vs2005下編譯一下就發現,居然報錯了!這又是為什麼呢?

看一下vs2005的報錯資訊吧,"error c2146: syntax error : missing ';' before identifier 'printf'",這個報錯資訊很準確,我們確實是漏掉了乙個分號,但是漏掉了也符合上面的分析啊,怎麼會被發現了呢?我感覺這種錯誤應該是lint之類的東西才能發現的,就像if(i = 1)之類的錯誤一樣,不過既然編譯器這麼報錯,我們就去翻一下c99標準吧,在6.5.3 unary operators的一開始syntax小節就能看到下面這個資訊:

從上圖可以明顯的看到sizeof後面跟資料型別的時候得有括號才行,如果是變數的話可以是沒有括號的形式(為了相容,用於變數名時加上括號也是可以的),所以vs2005就報錯了,因為我們最上面給出的程式相當於是"sizeof long double;",這樣顯然就不對了,那麼就是說其實錯的還是vc6,可能開發vc6時並沒有注意到這一點微妙的差別導致了這個問題,那麼如果確實想在vs2005下這麼使用該怎麼辦呢?那就是寫成這種形式,"sizeof((long double)printf("%d\n",a));"這樣就可以獲得和vc6相同的結果了。

為了證實確實是對printf()進行了強制型別轉換我們可以寫下面這個小程式來驗證一下。

#include 

<

stdio.h

>

void

foo(

inta)

intmain()

只是把printf()函式改成了foo()函式,但是這次vc6編譯時就報錯了,報錯資訊是"error c2069: cast of 'void' term to non-'void'",看,我們的foo()函式返回的是void型別,也就是說根本沒返回什麼,再進行強制型別轉換就會報錯了,我們也就可以確定使用printf()函式時不報錯就是因為成功地進行了轉換。

總結一下,我們可以知道使用sizeof操作符時,如果後面是變數名,那麼可以是sizeof a也可以是sizeof(a),但是如果後面是資料型別時,那麼就只能是sizeof(int)而不能是sizeof int。vc6編譯器就是因為對此的檢查不夠嚴格導致了這個微妙的小錯誤。

乙個有意思的問題

a b這個表示式如何理解?應該理解成a b還是a b,還是a b呢?應該按第一種方式理解。編譯的過程分為詞法解析和 語法解析兩個階段,在詞法解析階段,編譯器總是從前到後找最長的合法token。把這個表 達式從前到後解析,變數名a是乙個token,a後 面有兩個以上的 號,在c語言中乙個 號是合法的t...

乙個有意思的問題

最近做乙個交通管理系統,其中有個使用者投票功能。設想是直接開發乙個自定義的控制項。完成顯示,投票,ip檢索等全部功能。然而卻遇到乙個有意思的問題。具體來說就說,因為是用radiobuttonlist顯示的資料,在用radiobuttonlist.value捕獲使用者輸入時卻發現取出的索引始終為0.即...

乙個有意思的正則

在乙個框架中偶然發現一段比較有意思的正則,到現在還沒完全搞懂,先記錄下 1 3 str string 4 第乙個引數為正則 是左右定界符,就代表每個字串都匹配 5 preg split no empty 不返回空的 6 第 個引數 代表分割多少個陣列 7 chars preg split str,1...