2011-06-08 51 views
1

我試圖編譯後續的示例代碼:奇怪的使用strlen

#include <iostream> 
#include <stdio.h> 
#include <string> 
using namespace std; 

int main() 
{ 
    if (strlen <= 0) { 
    cout << "trace1" << endl; 
    return 0; 
    } 
    cout << "trace2" << endl; 
    return 0; 
} 

奇怪的是,它成功編譯。你有什麼想法,爲什麼?

我還沒有聲明strlen爲變量。

+0

無法重現:test.cpp:8:7:錯誤:'strlen'未在此範圍內聲明 – kay 2011-06-08 08:25:15

+0

您是自己編寫還是在某處找到它?另外,這不是C – Joe 2011-06-08 08:27:36

+0

這個代碼是C++。至少要適當標記它。 – Sriram 2011-06-08 08:30:00

回答

1

如果您對strlen以外的其他功能的操作相同,則此示例代碼將打印trace2,因爲strlen是指向函數size_t strlen (const char * str)的指針,其值應爲正數。

cout << (size_t *) strlen << endl; 
cout << (size_t *) strcat << endl; 

例如上面打印的代碼:

0x7fff84d29110 
0x7fff84d63953 

我的機器上(正如你看到的這些都是正數,因爲他們開始與7)。

此外,如果我打印strlenstrcat而不投射到(size_t *),結果將是1,這意味着這些函數是有效的。

+0

指針可能碰巧在系統上具有「正」值(對於簽名類型),但標準不保證可移植性 - 指針無論如何都傾向於無符號,所以'<= 0'等同於'== 0' 。另外,如果函數不知道,會出現編譯器錯誤,而不是具有負指針或NULL指針,所以'if(strlen <= 0)'代碼永遠不能執行;使程序非常愚蠢。 – 2011-06-08 09:00:45

+0

「不能保證可移植的標準」沒有意義。從邏輯上說,內存地址應該是正值,地址範圍保證它們將被存儲在一個帶符號的類型中,而不會溢出。 如果未聲明該函數,則會出現編譯器錯誤,但是((strlen == 1)或'(strlen> 0)'表示該函數有效。 – fardjad 2011-06-08 09:07:17

+1

從邏輯上講,地址不是數字,所以談論正面或負面的地址是沒有意義的。形式上,僅當兩個地址指向同一個表時才定義不等式的地址('<'等)的比較;因爲你不能有函數表,所以在指向函數的指針上使用'<='總是未定義的行爲。編譯器可以,也許應該警告它,但編譯器的作者可能沒有想到任何人都會嘗試這樣做。 – 2011-06-08 09:47:35

2

它可能衰變成衰減爲整數的地址。一個真正的編譯器可能會在屏幕上顯示警告。

+0

地址是什麼? – 2011-06-08 08:25:42

+0

@Salman函數'strlen'的地址 – cnicutar 2011-06-08 08:26:27

+0

準確地說,您可能想稍微修改一下您的答案! – 2011-06-08 08:37:40

4

僅使用函數的標識符衰減到相應類型的函數指針。在這種情況下,strlensize_t (*)(const char *)類型的指針。該指針保存可執行代碼中函數的第一條指令的地址。

測試該指針的值是合法的,無論原因可能是什麼,儘管在您提供的代碼片段中看起來很奇怪。

+0

它是合法的,但(strlen <= 0)的結果是* unspecified *。 「 – decltype 2011-06-08 08:34:27

+0

」該指針保存可執行代碼中函數的第一條指令的地址。「 - 不必要。例如,如果函數是啓用了互操作的ARM上的拇指代碼,則函數指針比內存中函數的開頭大1。 – 2011-06-08 11:31:17

3

strlen without()給你一個函數指針,指向strlen函數在內存中分配的地址。

如果庫函數strlen被分配在地址小於0的地址上(這在世界上的每臺計算機上都不可能),或者如果它分配在地址0(極其不可能但可能),則打印「trace1」。否則,如果strlen被分配到大於零的地址(最有可能的情況),它會打印「trace2」。