變量爭論函數如何將對象傳遞給struct/class? 例如:將對象傳遞給var arg函數
CString a_csName;
CString a_csAge(_T("20"));
a_csName.Format(_T("My Age is : %s"),a_csAge);
這裏CString::Format
是一個printf風格可變arguement函數,它接受這個CString
對象。這怎麼可能?
變量爭論函數如何將對象傳遞給struct/class? 例如:將對象傳遞給var arg函數
CString a_csName;
CString a_csAge(_T("20"));
a_csName.Format(_T("My Age is : %s"),a_csAge);
這裏CString::Format
是一個printf風格可變arguement函數,它接受這個CString
對象。這怎麼可能?
經過MFC代碼的一些研究和調試發現下面,希望它有助於誰面臨着名的靜態代碼分析器錯誤「將struct'CStringT'傳遞給省略號」,這實際上也是我懷疑的根源。
http://www.gimpel.com/html/bugs/bug437.htm
Format函數是一個可變參數函數,取決於存在於第一參量的格式說明符。第一個參數總是一個char *。
它分析格式說明符(%s,%d,%i ...),並根據找到的格式說明符的索引讀取var_arg數組,並直接轉換爲char * if%s或int if% d被指定。
因此,如果一個CString被指定並且相應的格式說明符是%s,那麼對CString對象進行char *的直接強制轉換嘗試。
CString a_csName;
CString a_csAge(_T("20"));
a_csName.Format(_T("My Age is : %s"),a_csAge);
wcout<<a_csName;
將打印我的年齡是20
CString a_csName;
CString a_csAge(_T("20"));
a_csName.Format(_T("My Age is : %d"),a_csAge);
wcout<<a_csName;
將打印我的年齡是052134
所以有這背後沒有任何情報。只是一個直接演員。因此,我們通過POD或用戶定義的數據結構,它沒有什麼差別。
你爲什麼回答你自己的問題? –
我研究了一下,調試了一下,發現了這個。因此思想會分享它。 – surega
來源:http://msdn.microsoft.com/en-us/library/aa300688%28v=vs.60%29.aspx
- 您可以爲const char *與LPCTSTR函數參數自由替代CString的對象。
大概CString
是沒有虛函數表的一類,並用僅char*
類型的屬性。這意味着sizeof(CString) == sizeof(const char*)
,並且如果您將一個CString
重新解析爲const char*
,那麼您將得到一個工作const char*
。
編譯器不應該接受將結構傳遞給函數的可變參數部分。但如果我沒有錯,在GCC中,當你將一個結構傳遞給可變參數時,它的內存被複制(即不使用拷貝構造函數)併發出警告。我猜MSVC在那裏做的是一樣的,然後,Format
方法只是假設給定的數據是const char*
。
讓我給你一個替代的例子。假設你有一個沒有vtable的類,只有成員是int。如果你把它傳遞給一個可變參數,編譯器會複製這個對象的內容,這只是一個int。在函數實現中,你(不知何故)知道你收到了一個int
。然後你查詢參數,詢問int
。因爲在內存級別上,你的班級與int
沒什麼區別,所以事情會「很好」。該函數將訪問該類的int
屬性。
那麼這是否意味着Format會接受任何只有const char *成員的結構?還是有一些CString對象的特殊處理? – surega
在代碼(而不是編譯器)級別有CString處理*特殊*處理對象在內存中的佈局非常仔細地管理以實現這種效果。一般來說,你不應該通過可變參數傳遞類對象。如果您絕對*必須*執行此操作,請將指針傳遞給該對象。 –
@surega編輯說明更好 –
我最近不得不清除這個Lint錯誤,並偶然發現這個線程。
雖然這是一個有趣的調查正在發生,避免lint警告的最簡單的方式轉換是通過使用CString的方法Get.String()
作爲傳遞CString的指針,而不是CString的結構如下
a_csName.Format(_T("My Age is : %d"), a_csAge.GetString());
讓我開始以不同的方式回答這個問題。
struct Value
{
int nValue;
float fOtherValue;
};
int main()
{
Value theValue;
theValue.nValue = 220;
theValue.fOtherValue = 3.14f;
printf("Value: %d", theValue);
}
此代碼將打印220
沒有任何問題。但是,如果你theValue
後通過第二個參數,它不會:
printf("Values: %d, %f", theValue, theValue.fOtherValue);
因爲第一可變參數theValue
不符合%d
參數指定的大小。因此,不會顯示3.14
(可能不會)。我們不要談論如何printf
,堆棧上的參數,va_start
和類似的東西的工作。
同樣,當我們設計一個String
類是這樣的:
struct String
{
char* pData;
public:
String()
{
pData = new char[40];
strcpy_s(pData, 40, "Sample");
}
};
而且使用這種方式:
String str;
printf("%s", str);
它肯定會工作。
但是參數和調用棧損壞呢?如果一個類的大小(如Value
)大於格式(%d
)所指定的數據大小(4爲Value
)會怎麼樣?那麼,在這種情況下,所設計的類需要確保給定類的大小與printf
函數使用的參數大小相同。
我不會提及它的細節,但CString
使用內部類CStringData
。後一類包含字符串,長度,參考計數等。CString
(實際CSimpleStringT
)使用此類,但只保留指針char
/wchar_t
,由CStringData
管理。
很大程度上,CString
實現爲String
類提到(只要數據和sizeof
去)。
使用可變參數模板的CString :: Format? CString是否只包含一個屬性,它是一個指向char的指針? –
void __cdecl CString :: Format(_In_ _Printf_format_string_ PCXSTR pszFormat,...); – surega
http://stackoverflow.com/questions/205529/c-c-passing-variable-number-of-arguments-around –