首页
社区
课程
招聘
[求助]关于变参....
发表于: 2010-7-31 18:27 7136

[求助]关于变参....

2010-7-31 18:27
7136
#define FLAG_END 0xDEAD
int ReadAddrB(int base,...)
{
__try
{
base = *(PINT)base;
int* arg_ptr = &base + 1;
int i=0;

while (arg_ptr[i] != FLAG_END)
base = *(PINT)(base + arg_ptr[i]);
}
__except(1)
{
base = FLAG_END;
}

return base;
}

这种变参,能不能在调用的时候让IDE/宏自动为我们加一个END_FLAG参数?
比如,
调用ReadAddrB(40000,4,4,4)时,
IDE识识为ReadAddrB(40000,4,4,4,END_FLAG)

手动添加怕忘了加,不安全,也不省事.

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (15)
雪    币: 203
活跃值: (11)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
下面给一个c中实现可变参数的例子:

#include <stdio.h>
#include <stdarg.h>

double fun(int va_num,...)
{
    double d1=1,d2=2,d3=3; //设置参数的默认值

    double tmp;
    int i;
    va_list va_args;
    va_start(va_args,va_num);

    for (i=0; i<va_num;++i )
    {
        tmp=va_arg(va_args,double);
        switch(i)
        {
            case 0:
                d1=tmp;
                break;
            case 1:
                d2=tmp;
                break;
            case 2:
                d3=tmp;
                break;
        }
    }
    va_end(va_args);
    printf("d1:%f d2:%f d3:%f \n",d1,d2,d3);
}

int main(void)
{
    fun(0);
    fun(1,(double)10);
    fun(2,(double)10,(double)20);
    fun(3,(double)10,(double)20,(double)30);

    return 0;
}
2010-7-31 19:16
0
雪    币: 137
活跃值: (410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
这个比结束还麻烦呢.
听人家说
vc的工程属性,C++/Preprocessor部分,可以直接加预定义的宏
就是不怎么弄
2010-7-31 23:04
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
嗯,麻烦么?va_list实现变参很正常啊,难道我火星了?
2010-8-1 00:48
0
雪    币: 998
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
都是用va_list。你自己加个结束标记多此一举,还容易遗漏。
2010-8-2 09:37
0
雪    币: 137
活跃值: (410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
LS,你看下va_list的宏定义再说话吧.va_list并没有参数个数...
2010-8-2 13:32
0
雪    币: 998
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
。。。这和有没有参数个数有什么关系。你要想得到参数个数,va_arg遍历的时候计数不就完事了么。

int count=0,i=base;
va_list(list);
va_start(list,base);
while(i!=-1)
{
  count++;
  i=va_arg(list,int);
}
2010-8-2 15:18
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
va_list的宏定义?不是typedef char * va_list么?

#include <stdio.h>
#include <stdarg.h>

int Average(int val,...)
{
        int total = 0;
        int num;
        int count = val;
        va_list valist;
        va_start(valist,val);
        while(val)
        {
                num = va_arg(valist,int);
                total = total + num;
                val--;
        }
        va_end(valist);                //据说不加这一句可能造成程序崩溃,但是这只是给一个char *指针赋值为空而已,没那么严重吧。
        return total/count;
}

int main(int argc,char *argv[])
{
        printf("%d\n",Average(3,1,2,3));
        printf("%d\n",Average(5,1,2,3,6,13));
        return 0;
}

参数个数不是有么?看va_start的宏也可以看到:#define va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) ),跳过了一个int类型的长度,这个长度恰好就是第一个参数,看反汇编就更清楚了:
	va_list valist;
	va_start(valist,val);
00411A6B  lea         eax,[ebp+0Ch]                        //显然跳过了在ebp+08h位置的第一个参数
00411A6E  mov         dword ptr [valist],eax 


被跳过的第一个参数应该就可以传递参数的个数了吧。
2010-8-2 17:32
0
雪    币: 137
活跃值: (410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
那跟2楼有什么区别,我就是想方便一下
2010-8-2 20:07
0
雪    币: 137
活跃值: (410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
5L跟7L,你说的是不是前后矛盾.
2010-8-2 20:09
0
雪    币: 998
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
矛盾?不知道你在说什么。我的意思是实际应用中都是用va_list这套东西,没见到谁自己添加个尾参数的。
2010-8-2 21:15
0
雪    币: 998
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
你那么做反而不方便。就算有预编译开关可以支持你的想法,那也不是具备移植性的做法。
2010-8-2 21:17
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
真不明白这还有什么好讨论的,自己查看ISO/IEC 9899:1999(E)标准嘛(C99标准),在7.15那一节,引用开头的一段:

7.15 Variable arguments <stdarg.h>
1 The header <stdarg.h> declares a type and defines four macros, for advancing
through a list of arguments whose number and types are not known to the called function
when it is translated.


然后介绍了va_start,va_arg,va_end和va_copy这四个宏。
2010-8-2 21:49
0
雪    币: 724
活跃值: (81)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
14
可以用如下宏解决,VC2005以后版本支持,宏支持变参也是C++标准。
#define ReadAddrB2(a,...) ReadAddrB(a,__VA_ARGS__,FLAG_END)

如:ReadAddrB2(1,2,3,4,5); 相当于:ReadAddrB(1,2,3,4,5,FLAG_END);
2010-8-3 19:34
0
雪    币: 137
活跃值: (410)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
万分感谢 14L
2010-8-4 11:18
0
雪    币: 401
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
真不明白,明明C语言提供了标准方法,为什么还是会选择编译器提供的方法呢?
以一个引用结束本帖的讨论吧,《C陷阱与缺陷》中文版,附录A(p145):
笔者经常见到某些程序还在使用printf函数中多年前就已基本废弃不用的特性,也见到另一些程序,明明要完成的任务利用varargs和stdarg可以做得干净利落、漂漂亮亮,但它们却使用了各种千奇百怪的杂凑招式,而且这些天知道怎么想出来的的办法也并不具有一般性,因而难以移植。
2010-8-4 12:39
0
游客
登录 | 注册 方可回帖
返回
//