使用可变参数的函数碰到的问题

red_berries 2008-08-20 09:19:16
我定义了下面的宏用来输出调试信息,但怪的是这个宏如果有多个参数就报错,但如果直接用DebugString就没错,比如

wchar_t *str = "Just for Test";

DebugString(L"Test : %s", str) //输出窗口正确输出调试信息
MYTRACE(L"Test : %s", str); //这样程序会崩掉
 

附宏定义代码如下:

#ifdef _DEBUG
#define MYTRACE(sz) DebugString(sz)
#else
#define MYTRACE(sz)
#endif

void DebugString(const wchar_t *format, ...);

#pragma warning(disable:4996)

const UINT DEBUG_BUFFER_SIZE = 1024;

void DebugString(const wchar_t *format, ...)
{
va_list arglist;
wchar_t buffer[DEBUG_BUFFER_SIZE];
va_start(arglist, format);
_vsnwprintf(buffer, DEBUG_BUFFER_SIZE, format, arglist);
va_end(arglist);
_tcsncat(buffer, _T("\n"), 1);
OutputDebugString(buffer);
}
#pragma warning(pop)
...全文
143 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
lbh2001 2008-08-22
  • 打赏
  • 举报
回复
对于变参函数,可能编译器直接忽略了你声明的调用约定,你跟踪一下汇编代码看看
red_berries 2008-08-22
  • 打赏
  • 举报
回复
回楼上,理论上是这样的,可我有__stacall定义变参函数也没问题。
lbh2001 2008-08-21
  • 打赏
  • 举报
回复
因为不确定变参函数的参数个数及类型,所以变参函数的参数必须从左至右压入栈,且由调用函数维持栈的平衡
这就是__cdecl调用约定,不知你用__stacall定义变参函数好像也没问题是什么样的
red_berries 2008-08-21
  • 打赏
  • 举报
回复
哦,谢谢各位了,另外再问个小问题,我用__stacall定义变参函数好像也没问题啊,我看有些文章说可变函数只能用__cdecl,到底怎么回事?
red_berries 2008-08-21
  • 打赏
  • 举报
回复
不行啊,如果没定义 MYTRACE 就会出错的。
lbh2001 2008-08-21
  • 打赏
  • 举报
回复
[Quote=引用 9 楼 red_berries 的回复:]
引用 5 楼 lbh2001 的回复:
DebugString(L"Test : %s", str)调用有两个参数
如何能用DebugString(sz)中的一个表示


宏替换的时候应该不看它是几个参数吧,个人觉得应该是括号中间的都应该给替换过来的吧

To akirya

__VA_ARGS__ 是什么宏?我这怎么没有这个的定义啊
[/Quote]

__VA_ARGS__ 在C99中定义

“宏替换的时候应该不看它是几个参数吧,个人觉得应该是括号中间的都应该给替换过来的吧”

#define Max(x,y) ((x)>(y)? (x):(y))

按照你的意思
Max(100,200)如何确定x和y,没有逗号分隔行吗
red_berries 2008-08-21
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 lbh2001 的回复:]
DebugString(L"Test : %s", str)调用有两个参数
如何能用DebugString(sz)中的一个表示
[/Quote]

宏替换的时候应该不看它是几个参数吧,个人觉得应该是括号中间的都应该给替换过来的吧

To akirya

__VA_ARGS__ 是什么宏?我这怎么没有这个的定义啊
yyyapple 2008-08-21
  • 打赏
  • 举报
回复
up
#ifdef _DEBUG
#define MYTRACE(s, ...) DebugString(s, __VA_ARGS__)
#else
#define MYTRACE(s, ...)
#endif

void DebugString(const wchar_t *format, ...);

#pragma warning(disable:4996)

const unsigned int DEBUG_BUFFER_SIZE = 1024;

void DebugString(const wchar_t *format, ...)
{
va_list arglist;
wchar_t buffer[DEBUG_BUFFER_SIZE];
va_start(arglist, format);
_vsnwprintf(buffer, DEBUG_BUFFER_SIZE, format, arglist);
va_end(arglist);
_tcsncat(buffer, _T("\n"), 1);
OutputDebugString(buffer);
}

#pragma warning(pop)
lbh2001 2008-08-21
  • 打赏
  • 举报
回复
我记得变长参数宏是C99新增的
况且lz的MYTRACE宏定义并未使用...
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 lbh2001 的回复:]
DebugString(L"Test : %s", str)调用有两个参数
如何能用DebugString(sz)中的一个表示
[/Quote]
使用变长参数宏,但不通用的东西
// variadic_macros.cpp
#include <stdio.h>
#define EMPTY

#define CHECK1(x, ...) if (!(x)) { printf(__VA_ARGS__); }
#define CHECK2(x, ...) if ((x)) { printf(__VA_ARGS__); }
#define CHECK3(...) { printf(__VA_ARGS__); }
#define MACRO(s, ...) printf(s, __VA_ARGS__)

int main() {
CHECK1(0, "here %s %s %s", "are", "some", "varargs1(1)\n");
CHECK1(1, "here %s %s %s", "are", "some", "varargs1(2)\n"); // won't print

CHECK2(0, "here %s %s %s", "are", "some", "varargs2(3)\n"); // won't print
CHECK2(1, "here %s %s %s", "are", "some", "varargs2(4)\n");

// always invokes printf in the macro
CHECK3("here %s %s %s", "are", "some", "varargs3(5)\n");

MACRO("hello, world\n");
// MACRO("error\n", EMPTY); would cause C2059
}
lbh2001 2008-08-21
  • 打赏
  • 举报
回复
DebugString(L"Test : %s", str)调用有两个参数
如何能用DebugString(sz)中的一个表示
red_berries 2008-08-21
  • 打赏
  • 举报
回复
ls这样是可以,能否指引一下为什么#define MYTRACE(sz) DebugString(sz) 会出错吗?
seufl 2008-08-21
  • 打赏
  • 举报
回复
应该是从右往左压入堆栈吧,这样最左边的参数在堆栈中的偏移是确定的,通常应该是在返回地址的下面一个位置
_cdecl调用约定是让调用者负责完成清理堆栈的工作,因为对变长参数的函数,只有调用者知道他压了几个参数到堆栈
red_berries 2008-08-21
  • 打赏
  • 举报
回复
[Quote=引用 12 楼 lbh2001 的回复:]
因为不确定变参函数的参数个数及类型,所以变参函数的参数必须从左至右压入栈,且由调用函数维持栈的平衡
这就是__cdecl调用约定,不知你用__stacall定义变参函数好像也没问题是什么样的
[/Quote]

就是下面的这样定义的,变参也可以输出


#ifdef _DEBUG
#define MYTRACE(s, ...) DebugString(s, __VA_ARGS__)
#else
#define MYTRACE(s, ...)
#endif

void WINAPI DebugString(const wchar_t *format, ...);

#pragma warning(disable:4996)

const unsigned int DEBUG_BUFFER_SIZE = 1024;

void WINAPI DebugString(const wchar_t *format, ...)
{
va_list arglist;
wchar_t buffer[DEBUG_BUFFER_SIZE];
va_start(arglist, format);
_vsnwprintf(buffer, DEBUG_BUFFER_SIZE, format, arglist);
va_end(arglist);
_tcsncat(buffer, _T("\n"), 1);
OutputDebugString(buffer);
}

#pragma warning(pop)

Zark 2008-08-21
  • 打赏
  • 举报
回复
#ifdef _DEBUG
#define MYTRACE(sz) DebugString(sz)
#else
#define MYTRACE(sz)
#endif

这个宏定义是错的, 达不到你要求的效果.

#ifdef _DEBUG
#define MYTRACE DebugString
#else
#define MYTRACE(sz)
#endif
这样是可以的.

yuhaozx 2008-08-21
  • 打赏
  • 举报
回复
1、
学习
  • 打赏
  • 举报
回复
#define MYTRACE DebugString
不就行了么?

69,373

社区成员

发帖
与我相关
我的任务
社区描述
C语言相关问题讨论
社区管理员
  • C语言
  • 花神庙码农
  • 架构师李肯
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧