变量争论函数如何将对象传递给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 –