社区
C语言
帖子详情
__stdcall 可以像__cdecl 使用可变参数吗??
testtest2002
2011-03-18 03:39:04
像这样:
void __cdecl operator()(DWORD_PTR dwCategory, UINT nLevel, const char *pszFmt, ...)
...全文
235
14
打赏
收藏
__stdcall 可以像__cdecl 使用可变参数吗??
像这样: void __cdecl operator()(DWORD_PTR dwCategory, UINT nLevel, const char *pszFmt, ...)
复制链接
扫一扫
分享
转发到动态
举报
AI
作业
写回复
配置赞助广告
用AI写文章
14 条
回复
切换为时间正序
请发表友善的回复…
发表回复
打赏红包
BianChengNan-BCN-BCN
2011-12-30
打赏
举报
回复
[Quote=引用 13 楼 maozefa 的回复:]
引用 10 楼 dourgulf 的回复:
maozefa
已经解析得很清楚了,只是对“使用插入汇编手工清除变参部分”认为不是很现实,本质上只有调用者(caller)负责处理参数的堆栈才可以正确实现变参数的清理,所以一个函数的编写者是无法在函数的实现中进行具体的参数堆栈清理工作(即使嵌入汇编),实际上C对变参数的支持是在编译的时候对调用参数加入清理堆栈的处理的:形式代码如下:
声明:
……
[/Quote]多谢maozefa,我看了一下汇编代码,是由系统平衡的堆栈,可是你上面说的参数将留在堆栈中,我不明白,既然系统已经帮助清理了堆栈,怎么还会残留呢?请指教
阿发伯
2011-03-19
打赏
举报
回复
[Quote=引用 10 楼 dourgulf 的回复:]
maozefa
已经解析得很清楚了,只是对“使用插入汇编手工清除变参部分”认为不是很现实,本质上只有调用者(caller)负责处理参数的堆栈才可以正确实现变参数的清理,所以一个函数的编写者是无法在函数的实现中进行具体的参数堆栈清理工作(即使嵌入汇编),实际上C对变参数的支持是在编译的时候对调用参数加入清理堆栈的处理的:形式代码如下:
声明:
void func(int, ...);
调……
[/Quote]
对定义了变参的__sdtcall插入汇编手工清栈是可行的。只不过,我刚才想测试一下,却无法办到,因为C编译器遇到__stdcall中带变参,就自动按__cdecl处理了(我用的BCB2007)。我想这才是LZ“可以编译并运行成功”的真正原因。如果LZ会反汇编,如果查看一下你的函数最后的ret指令:如果是ren xxxx(数字)则是按__stdcall编译的,没有xxxx则是忽略了你的__stdcall定义!
漫步者、
2011-03-19
打赏
举报
回复
[Quote=引用 6 楼 testtest2002 的回复:]
可是我测试了这个代码,可以编译并运行成功,
void _stdcall OutputDebugStringf( char *fmt, ... )
{
va_list args;
char buf[DPRINTF_BUF_SZ];
va_start( args, fmt );
vsprintf( buf, fmt, args );
OutputDebugStringA( buf )……
[/Quote]//标准的调用函数,可变函数在stdrag.h文件中
Lactoferrin
2011-03-19
打赏
举报
回复
[Quote=引用 10 楼 dourgulf 的回复:]
maozefa
已经解析得很清楚了,只是对“使用插入汇编手工清除变参部分”认为不是很现实,本质上只有调用者(caller)负责处理参数的堆栈才可以正确实现变参数的清理,所以一个函数的编写者是无法在函数的实现中进行具体的参数堆栈清理工作(即使嵌入汇编),实际上C对变参数的支持是在编译的时候对调用参数加入清理堆栈的处理的:形式代码如下:
声明:
void func(int, ...);
调……
[/Quote]
可以在显式规定的参数中指明可变参数的个数,这样就可以手工退栈
子达如何
2011-03-19
打赏
举报
回复
maozefa
已经解析得很清楚了,只是对“使用插入汇编手工清除变参部分”认为不是很现实,本质上只有调用者(caller)负责处理参数的堆栈才可以正确实现变参数的清理,所以一个函数的编写者是无法在函数的实现中进行具体的参数堆栈清理工作(即使嵌入汇编),实际上C对变参数的支持是在编译的时候对调用参数加入清理堆栈的处理的:形式代码如下:
声明:
void func(int, ...);
调用:
func(foo,bar1,bar2);
汇编(伪代码):
PUSH foo
PUSH bar1
PUSH bar2
CALL FUNC
POP
POP
POP
如果是函数自己负责清理堆栈则:
void func(int foo, int bar1)
{
//实现
//编译器加入代码:
POP
POP
}
调用时候:
PUSH foo
PUSH bar1
CALL func
//OK
对比而言,后者产生的代码要小一点点
阿发伯
2011-03-19
打赏
举报
回复
补充一点:如果调用__stdcall函数后,使用插入汇编手工清除变参部分,也是可以的。这也就是为什么LZ“可以编译并运行成功”的原因。
阿发伯
2011-03-19
打赏
举报
回复
所以,__stdcall定义变参,不是编译系统支不支持的问题,而是不能在__stdcall中定义变参,这是一个基本常识。
阿发伯
2011-03-19
打赏
举报
回复
[Quote=引用 6 楼 testtest2002 的回复:]
可是我测试了这个代码,可以编译并运行成功,
void _stdcall OutputDebugStringf( char *fmt, ... )
{
va_list args;
char buf[DPRINTF_BUF_SZ];
va_start( args, fmt );
vsprintf( buf, fmt, args );
OutputDebugStringA( buf )……
[/Quote]
__cdecl是由调用函数者清栈(参数所占内存),这个编译系统可以帮你处理;_stdcall是由被调用函数清栈,而被调用函数只能按固定形参个数清除,如此一来,变参部分所占内存会一直保存在程序栈中而得不到清除。
如果频繁使用变参调用这个函数,将会使系统崩溃!因为C/C++的栈是很有限的。
testtest2002
2011-03-19
打赏
举报
回复
可是我测试了这个代码,可以编译并运行成功,
void _stdcall OutputDebugStringf( char *fmt, ... )
{
va_list args;
char buf[DPRINTF_BUF_SZ];
va_start( args, fmt );
vsprintf( buf, fmt, args );
OutputDebugStringA( buf );
char buf1[1024];
sprintf( buf1,"file : %s (%d)", __FILE__,__LINE__);
OutputDebugStringA(buf1);
}
这是为什么???
ouyh12345
2011-03-18
打赏
举报
回复
不能,只有__cdecl支持变参
「已注销」
2011-03-18
打赏
举报
回复
The __stdcall calling convention is used to call Win32 API functions. The callee cleans the stack, so the compiler makes vararg functions __cdecl.
hedy007
2011-03-18
打赏
举报
回复
vc++ 6.0可以的。
superarhow
2011-03-18
打赏
举报
回复
不行。因为stdcall是由被调用端清理堆栈的,被调用端是不知道调用端传了多少参数的。不过可以用变通的方法实现。
bdmh
2011-03-18
打赏
举报
回复
应该不支持
函数的调用规则(__
cd
ecl
,__
std
call,__fastcall,__pascal)
函数的调用规则(__
cd
ecl
,__
std
call,__fastcall,__pascal) 关于函数的调用规则(调用约定),大多数时候是不需要了解的,但是如果需要跨语言的编程,比如VC写的dll要delphi调用,则需要了解。 microsoft的vc默认的是__
cd
ecl
方式,而windows API则是__
std
call,如果用vc开发dll给其他语言用,则应该指定__
std
call方式。堆栈由谁清除这个很重要,如果是要写汇编函数给C调用,一定要小心堆栈的清除工作,如果是__
cd
ecl
方式的函数,则函数本身(如果不用汇编写)则不需要关心保存参数的堆栈的清除,但是如果是__
std
call的规则,一定要在函数退出(ret)前恢复堆栈。
关于函数调用方式__
std
call和__
cd
ecl
详解
下面小编就为大家带来一篇关于函数调用方式__
std
call和__
cd
ecl
详解。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
__
std
call调用约定、C调用约定和__fastcall调用约定
__
std
call调用约定、C调用约定和__fastcall调用约定 __
std
call调用约定、C调用约定和__fastcall调用约定 __
std
call调用约定、C调用约定和__fastcall调用约定 __
std
call调用约定、C调用约定和__fastcall调用约定
MFC中
std
call调用约定
调用约定的讲解,对_
std
call 的理解(上) 在C语言中,假设我们有这样的一个函数:int function(int a,int b) 调用时只要用result = function(1,2)这样的方式就可以
使用
这个函数。
浅谈C/C++中
可变参数
的原理
要理解
可变参数
,首先要理解函数调用约定, 为什么只有__
cd
ecl
的调用约定支持
可变参数
,而__
std
call不支持? 实际上__
cd
ecl
和__
std
call函数参数都是从右到左入栈,它们的区别在于由谁来清栈,__
cd
ecl
由外部调用函数清栈,而__
std
call由被调用函数本身清栈, 显然对于
可变参数
的函数,函数本身没法知道外部函数调用它时传了多少参数,所以没法支持被调用函数本身清栈(__
std
call), 所以
可变参数
只能用__
cd
ecl
l。 另外还要理解函数参数传递过程中堆栈是如何生长和变化的,从堆栈低地址到高地址,依次存储 被调用函数局部变量,上一函数堆栈桢基址,函数
C语言
70,024
社区成员
243,263
社区内容
发帖
与我相关
我的任务
C语言
C语言相关问题讨论
复制链接
扫一扫
分享
社区描述
C语言相关问题讨论
社区管理员
加入社区
获取链接或二维码
近7日
近30日
至今
加载中
查看更多榜单
社区公告
暂无公告
试试用AI创作助手写篇文章吧
+ 用AI写文章