将对象传递给var arg函数
passing an object to var arg function
CString a_csName;
CString a_csAge(_T("20"));
a_csName.Format(_T("My Age is : %s"),a_csAge);
这里CString::Format
是一个printf风格的变量argument函数,它接受这个CString
对象。这怎么可能?
通过MFC代码进行了一些研究和调试后,发现了以下内容,希望它能帮助那些面临著名的静态代码分析器错误"将结构体'CStringT'传递给省略号"的人,这实际上也是我怀疑的来源。
http://www.gimpel.com/html/bugs/bug437.htm
Format函数是一个可变函数,取决于第一个参数中的格式说明符。第一个参数始终是char*。
它解析格式说明符(%s、%d、%i…(,并根据找到的格式说明符的索引读取var_arg数组,如果指定了%s,则直接转换为char*或int。
因此,如果指定了一个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或用户定义数据结构,它没有什么区别。
来源:http://msdn.microsoft.com/en-us/library/aa300688%28v=vs.60%29.aspx
- 您可以自由地用CString对象替换const char*和LPCTSTR函数参数
可能CString
是一个没有vtable的类,并且只有一个类型为char*
的属性。这意味着sizeof(CString) == sizeof(const char*)
,并且如果将CString
重新解释为const char*
,则会得到一个工作的const char*
。
编译器不应接受将结构传递给函数的可变部分。但如果我没有错的话,在GCC中,当你将一个结构作为变量参数传递给时,它的内存会被复制(即没有使用复制构造函数(,并发出警告。我猜MSVC在那里也在做同样的事情,然后,Format
方法只是假设给定的数据是const char*
。
让我给你举一个替代的例子。假设你有一个没有vtable的类,它只有成员是int。如果你把它传递给一个可变参数,编译器会复制这个对象的内容,这只是一个int。在函数实现中,你(不知何故(知道你收到了一个int
。然后查询参数,要求int
。由于在内存级别上,您的类与int
没有什么不同,所以一切都会"正常"工作。该函数将访问类的int
属性。
我最近不得不清除这个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
(指定的数据大小(对于Value
为4(,该怎么办。在这种情况下,设计的类需要确保给定类的大小与printf
函数使用的参数大小相同。
我不会提及有关它的详细信息,但CString
使用内部类CStringData
。后一个类保存字符串、长度、引用计数等。CString
(实际上是CSimpleStringT
(使用这个类,但只保存由CStringData
管理的char
/wchar_t
的指针。
在很大程度上,CString
被实现为所提到的String
类(就数据和sizeof
而言(。
- 如何在 C 中正确使用 libiconv 使其不会报告"Arg list too long"?
- 将 N-arg 函数包装到另一个函数中
- 使用 getline(cin, var) 两次在进行字符串比较时会产生错误 (==)
- ( var > x) 和 ( x < var)之间有什么区别吗?
- 使用显式模板参数列表和 [temp.arg.explicit]/3 的函数调用的演绎失败
- 为什么不接受具有默认分配参数的函数作为 0-arg 生成器?
- C++重载解析总是诉诸别名 arg. 而不是其他人作为对所有人都有效的 arg.
- 区分两个零arg构造函数的惯用方法
- 如果使用返回引用的函数初始化"auto"var,为什么它不声明引用类型?
- 将 mnist 客户端重写为 c++(arg[0] 不是矩阵)
- 在现代 c++ 中,有什么好方法可以获取 arg 类型列表表单函数指针吗?
- FileIO,写入文档,var = 1.0 变为 1
- 解释一下这个宏是如何工作的?[C 中的打印var名称]
- 与现有VAR无法实现结构化结合
- 范围分辨率运算符在类型:: var的情况下返回什么
- 为什么在 var 未更新的情况下使用,仅在启动 var 后打印
- 如何使用 z3 中的 arg() 函数
- 为什么有必要将"this"指针作为"arg"参数传递给pthread_create
- var 已更改为 1,并带有 "if (var = 0 || var == 0)" 语句
- 将对象传递给var arg函数