簡體   English   中英

Visual Studio是否在打印功能地址時出錯?

[英]Is Visual Studio buggy in printing the function address?

使用以下測試用例:

#include <iostream>

void foo()
{}

int main()
{
   std::cout << &foo << std::endl;
}

GCC 4.1.2,GCC 4.8和GCC 4.9(C ++ 03和C ++ 11)在構建和編譯時都給出以下輸出

$ g++ main.cpp -o test && ./test
main.cpp: In function 'int main()':
main.cpp:8:23: warning: the address of 'void foo()' will always evaluate as 'true' [-Waddress]
   std::cout << &foo << std::endl;
                 ^
1

這應該是因為函數指針唯一可行的流插入是轉換為bool (並且需要轉換為void*以實際獲取流中的地址)。

但是,Microsoft Visual Studio 2012和2013會輸出指針地址。

哪一套工具鏈符合要求? 是否記錄了不合格?

如果禁用語言擴展( /Za開關),可以使MSVC正常運行並執行從函數指針到bool的轉換。 如果這樣做,您的代碼會產生以下警告(在VS2013上為/W4

1>main.cpp(8): warning C4305: 'argument' : truncation from 'void (*)(void)' to 'std::_Bool'
1>main.cpp(8): warning C4800: 'void (*)(void)' : forcing value to bool 'true' or 'false' (performance warning)

輸出為1


這種行為被記錄下的類型轉換部分

C ++編譯器和C編譯器都支持這些非ANSI轉換:
...
非ANSI轉換為指向數據指針的函數指針

果然,以下行僅在/Za禁用時編譯

void *p = &foo;

禁用語言擴展會產生錯誤消息

1>main.cpp(8): error C2440: 'initializing' : cannot convert from 'void (*)(void)' to 'void *'
1>          There is no context in which this conversion is possible

至少通過我閱讀N3337,gcc是正確的,MSVC是不正確的(除非你禁用它的擴展名)。

路徑從標准的§4開始:

標准轉化是具有內置含義的隱式轉化。 第4條列舉了全套此類轉換。

因此,唯一存在的標准轉換是第4節中列出的轉換。但並非每種可能的標准轉換都適用於所有情況。 只能使用符合標准轉換序列的那些。 標准轉換序列規定如下:

- 來自以下集合的零或一次轉換:左值到右值的轉換,數組到指針的轉換以及函數到指針的轉換。
- 來自以下集合的零或一次轉換:整數促銷,浮點促銷,積分轉換,浮點轉換,浮點積分轉換,指針轉換,成員轉換指針和布爾轉換。
- 零或一個資格轉換。

這里我們從指向函數的指針開始,因此第一個項目符號點下的轉換不適用。 我們不需要/關心資格轉換,所以我們也不關心第三個要點。

要將pointer to function轉換pointer to functionpointer to void轉換pointer to void ,顯然是指針轉換。 這些正好有三個品種。 在§4.10/ 1,我們有從空指針常量開始的指針轉換(這里顯然不適用)。 §4.10/ 2涵蓋從以下各項開始的轉換:

類型為“指向cv T的指針”的prvalue,其中T是對象類型[...]

這顯然也不適用於此,因為函數不是對象。 第三種選擇是:

類型為“指向cv D的指針”的prvalue,其中D是類類型[...]

同樣,函數不是類類型,因此也不能應用。

這使我們只有一個選項:直接從“指向函數的指針”到“布爾”的單個轉換。 當然,這是一個布爾轉換。 §4.12說:

算術,無范圍枚舉,指針或指向成員類型的指針的prvalue可以轉換為bool類型的prvalue。

因此,當且僅當1)它是prvalue時,我們的值才能轉換為布爾值,並且2)它是指針。 這似乎很明顯,但如果我們想確認,我們可以在§5.3.1/ 2和5.3.1 / 3中查看運算符地址的定義:

以下每個一元運算符的結果都是prvalue。

這滿足了第一個要求。

一元&運算符的結果是指向其操作數的指針。 操作數應為左值或限定ID。 如果操作數是一個qualified-id,命名一個類型為T的某個類C的非靜態成員m,則結果的類型為“指向類型為C的C類成員的指針”,並且是一個指定C :: m的prvalue。 否則,如果表達式的類型是T,則結果具有“指向T的指針”,並且是作為指定對象(1.7)的地址的prvalue或指向指定函數的指針。 [強調補充]

這顯然符合第二個要求 - 結果是一個指針。

由於滿足了這些要求,轉換可能/將會發生。 轉換結果如下(返回§4.12):

零值,空指針值或空成員指針值轉換為false; 任何其他值都轉換為true。

因為我們從指向實際函數的指針開始,所以我們不能有空指針。 這只留下一種可能性:“任何其他值都轉換為真。”

正如gcc所說的那樣,轉換的唯一可能結果是布爾值為true 默認情況下將打印為“1”,如果boolalpha設置為true, boolalpha “true”。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM