C语言函数参数可变问题

icyice1989 2011-06-25 05:01:35

#include <stdio.h>
#include <string.h>

int myvsprintf(char *buf, const char *fmt, char *args)
{
char* p;
char tmp[256];
char* p_next_arg = args;

for (p=buf;*fmt;fmt++) {
if (*fmt != '%') {
*p++ = *fmt;
continue;
}

fmt++;

switch (*fmt) {
case 'x':
//itoa(tmp, *((int*)p_next_arg));
sprintf(tmp, "%d", *((int*)p_next_arg));
printf("%d", *((int*)p_next_arg));
strcpy(p, tmp);
p_next_arg += 4;
p += strlen(tmp);
break;
case 's':
break;
default:
break;
}
}

return (p - buf);
}

int myprintf(const char *fmt, ...)
{
int i, j;
char buf[256];
char* arg;
arg = ((char*)(&fmt) + 4); /*4是参数fmt所占堆栈中的大小*/

i = myvsprintf(buf, fmt, arg);
for(j = 0; j < i; j++)
{
putchar(buf[i]);
}
return i;
}
int main()
{
myprintf("%x", 1);
return 0;
}



代码从一个操作系统实现里摘出来的,但是调用myprintf时,参数压栈,然后在gdb调试时myprintf里的arg的值并不是1。不知道哪里错了。
...全文
190 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
icyice1989 2011-06-26
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 coding_hello 的回复:]

windows下测试,没问题。仔细调试一下啊,看看参数传进去后,再取出来时,值对不对。
[/Quote]
那我到windows下试试看。
linux我用gdb调的,在main函数栈里是可以看到两个参数入栈,这两个参数在栈中位置都可以找到。
在myprintf栈里,const char *fmt 我也找到了,但没有找到后面的1在栈中位置就没找到了。
这里&fmt应该是myprintf函数栈中的地址,+4后能对应到myprintf的第二个参数吗?
icyice1989 2011-06-26
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 c395565746c 的回复:]

arg = ((char*)(&fmt) + 4); /*4是参数fmt所占堆栈中的大小*/
难道应该是
arg = ((char*)(&fmt) - 4); /*4是参数fmt所占堆栈中的大小*/
[/Quote]
不是,栈是从高地址到低地址,
然后函数压栈是从右到左,至少vs下和gcc都是
AnYidan 2011-06-26
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 yq_118 的回复:]

可变长参数就用<stdarg.h>
没必要重复造车
[/Quote]

不建议使用可变长参数 -- compiler 不能效验参数类型
icyice1989 2011-06-26
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 yq_118 的回复:]

可变长参数就用<stdarg.h>
没必要重复造车
[/Quote]
呵呵,我看到这个原理,想验证一下的~
5t4rk 2011-06-25
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 dizuo 的回复:]

lz参考一下:
C/C++ code

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

//-----------------------------------------------------------------------------
t……
[/Quote]
++
dai0618 2011-06-25
  • 打赏
  • 举报
回复
都妈的大牛!
stein42 2011-06-25
  • 打赏
  • 举报
回复
可变长参数就用<stdarg.h>
没必要重复造车
ryfdizuo 2011-06-25
  • 打赏
  • 举报
回复
lz参考一下:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>

//-----------------------------------------------------------------------------
typedef char * va_list;

#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )

#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
//-----------------------------------------------------------------------------

/*
* A simple printf function. Only support the following format:
* Code Format
* %c character
* %d signed integers
* %i signed integers
* %s a string of characters
* %o octal
* %x unsigned hexadecimal
*/
int my_printf( const char* format, ...)
{
va_list arg;
int done = 0;

va_start (arg, format);
//done = vfprintf (stdout, format, arg);

while( *format != '\0')
{
if( *format == '%')
{
if( *(format+1) == 'c' )
{
char c = (char)va_arg(arg, int);
putc(c, stdout);
} else if( *(format+1) == 'd' || *(format+1) == 'i')
{
char store[20];
int i = va_arg(arg, int);
char* str = store;
itoa(i, store, 10);
while( *str != '\0') putc(*str++, stdout);
} else if( *(format+1) == 'o')
{
char store[20];
int i = va_arg(arg, int);
char* str = store;
itoa(i, store, 8);
while( *str != '\0') putc(*str++, stdout);
} else if( *(format+1) == 'x')
{
char store[20];
int i = va_arg(arg, int);
char* str = store;
itoa(i, store, 16);
while( *str != '\0') putc(*str++, stdout);
} else if( *(format+1) == 's' )
{
char* str = va_arg(arg, char*);
while( *str != '\0') putc(*str++, stdout);
}

// Skip this two characters.

format += 2;
} else {
putc(*format++, stdout);
}
}

va_end (arg);

return done;
}
野男孩 2011-06-25
  • 打赏
  • 举报
回复
windows下测试,没问题。仔细调试一下啊,看看参数传进去后,再取出来时,值对不对。
thunder_2011 2011-06-25
  • 打赏
  • 举报
回复
char ** arg = &fmt;

然后拿arg去偏移就可以了, 如果第二个是整数1,*(int *)(arg + 1) 就是 1 了

「已注销」 2011-06-25
  • 打赏
  • 举报
回复
arg = ((char*)(&fmt) + 4); /*4是参数fmt所占堆栈中的大小*/
难道应该是
arg = ((char*)(&fmt) - 4); /*4是参数fmt所占堆栈中的大小*/

69,377

社区成员

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

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