我需要在C中实现自己的printf函数。但是我在使用省略号(" ...")功能时遇到问题(我们需要使用省略号)。
根据我的教科书,传递给带省略号的函数的参数应该位于存储第一个参数的正上方的堆栈上。我找不到任何我在堆栈中传递的附加参数!这是我用来测试我的函数和输出的一些代码:
#include<stdio.h>
#include<stdlib.h>
int myprintf(char *str, ...)
{
//test code to view data around str on the stack:
int i;
for (i = -8; i <= 8; i++)
{
char *ptr = str + (i * 4); // ptr will iterate through the 8 bytes above and
// below str[0] on the stack
printf ("Bytes from str: %+03d \t
Ptr Addr: %x \t
Val int: %d \t
Val char: %c \n",
(i*4), ptr, *ptr, *ptr);
}
//my implementation of printf...
}
int main(void)
{
myprintf("test string", 1111, 2222, 3333);
}
这是myprintf函数的输出(堆栈的打印输出):
Bytes from str: -32 Ptr Addr: 8048922 Val int: 48 Val char: 0
Bytes from str: -28 Ptr Addr: 8048926 Val int: 97 Val char: a
Bytes from str: -24 Ptr Addr: 804892a Val int: 104 Val char: h
Bytes from str: -20 Ptr Addr: 804892e Val int: 32 Val char:
Bytes from str: -16 Ptr Addr: 8048932 Val int: 0 Val char:
Bytes from str: -12 Ptr Addr: 8048936 Val int: 118 Val char: v
Bytes from str: -08 Ptr Addr: 804893a Val int: 93 Val char: ]
Bytes from str: -04 Ptr Addr: 804893e Val int: 37 Val char: % <- my other variables should be here and above
Bytes from str: +00 Ptr Addr: 8048942 Val int: 116 Val char: t <-"test string"
Bytes from str: +04 Ptr Addr: 8048946 Val int: 32 Val char: <-" string"
Bytes from str: +08 Ptr Addr: 804894a Val int: 105 Val char: i <-"ing"
Bytes from str: +12 Ptr Addr: 804894e Val int: 0 Val char:
Bytes from str: +16 Ptr Addr: 8048952 Val int: 3 Val char:
Bytes from str: +20 Ptr Addr: 8048956 Val int: 0 Val char:
Bytes from str: +24 Ptr Addr: 804895a Val int: 0 Val char:
Bytes from str: +28 Ptr Addr: 804895e Val int: -1 Val char: �
Bytes from str: +32 Ptr Addr: 8048962 Val int: 0 Val char:
据我所知,值1111,2222和3333应位于此堆栈打印输出的某处。当我进行函数调用时,这些值会在哪里?
编辑:我不能使用&#34; stdarg.h&#34;我的实现中的库。答案 0 :(得分:5)
您正在尝试编写可变参数(有时称为varargs)函数。幸运的是,有标准的C库函数可以帮助您管理已经在堆栈上传递的参数。
您需要va_start
va_end
,va_next
和va_copy
来帮助您。给出的典型例子是:
#include <stdio.h>
#include <stdarg.h>
void
foo(char *fmt, ...)
{
va_list ap;
int d;
char c, *s;
va_start(ap, fmt);
while (*fmt)
switch (*fmt++) {
case 's': /* string */
s = va_arg(ap, char *);
printf("string %s\n", s);
break;
case 'd': /* int */
d = va_arg(ap, int);
printf("int %d\n", d);
break;
case 'c': /* char */
/* need a cast here since va_arg only
takes fully promoted types */
c = (char) va_arg(ap, int);
printf("char %c\n", c);
break;
}
va_end(ap);
}
点击此处的文档:http://linux.die.net/man/3/va_start
如果您不必兼容标准,GCC甚至还有一个函数属性,您可以将其应用于该函数,以指示您需要printf样式格式说明符。如果你使用它,GCC甚至可以为你做一些类型检查并发出警告,好像你的可变参数函数是printf。它可以方便地编写日志功能等。它已经存在了很长时间。 https://gcc.gnu.org/onlinedocs/gcc-5.3.0/gcc/Function-Attributes.html
答案 1 :(得分:2)
您的错误在这里:
char *ptr = str + (i * 4); // ptr will iterate through the 8 bytes above and
那不是你想做的事情。您正在查看字符串周围的内存,而不是指向字符串的指针周围的内存。将其更改为
char *ptr = &str + (i * 4); // ptr will iterate through the 8 bytes above and
正如@Joe所说,除了非常专业的需求外,这是解决问题的错误方法,你应该使用stdarg.h。
答案 2 :(得分:2)
此程序的行为可能不符合规范,但是对于从堆栈中搜索参数的实验,您必须移动指针指向参数而不是指针传递 as 参数。
#include<stdio.h>
#include<stdlib.h>
int myprintf(char *str, ...)
{
//test code to view data around str on the stack:
int i;
for (i = -8; i <= 8; i++)
{
/* add & before str to get the address of the argument */
char *ptr = (char*)&str + (i * 4); // ptr will iterate through the 4 * 8 bytes above and
// below str on the stack
printf ("Bytes from str: %+03d \t"
"Ptr Addr: %p \t"
"Val int: %d \t"
"Val char: %02X \n",
(i*4), (void*)ptr, *(int*)ptr, (unsigned int)(unsigned char)*ptr);
}
//my implementation of printf...
return 0;
}
int main(void)
{
myprintf("test string", 1111, 2222, 3333);
return 0;
}
导致我的本地环境:
Bytes from str: -32 Ptr Addr: 0028FF10 Val int: 213 Val char: D5
Bytes from str: -28 Ptr Addr: 0028FF14 Val int: 1662423109 Val char: 45
Bytes from str: -24 Ptr Addr: 0028FF18 Val int: -2 Val char: FE
Bytes from str: -20 Ptr Addr: 0028FF1C Val int: 1972834658 Val char: 62
Bytes from str: -16 Ptr Addr: 0028FF20 Val int: 2130567168 Val char: 00
Bytes from str: -12 Ptr Addr: 0028FF24 Val int: 0 Val char: 00
Bytes from str: -08 Ptr Addr: 0028FF28 Val int: 0 Val char: 00
Bytes from str: -04 Ptr Addr: 0028FF2C Val int: 4227938 Val char: 62
Bytes from str: +00 Ptr Addr: 0028FF30 Val int: 4235431 Val char: A7
Bytes from str: +04 Ptr Addr: 0028FF34 Val int: 1111 Val char: 57
Bytes from str: +08 Ptr Addr: 0028FF38 Val int: 2222 Val char: AE
Bytes from str: +12 Ptr Addr: 0028FF3C Val int: 3333 Val char: 05
Bytes from str: +16 Ptr Addr: 0028FF40 Val int: 0 Val char: 00
Bytes from str: +20 Ptr Addr: 0028FF44 Val int: 0 Val char: 00
Bytes from str: +24 Ptr Addr: 0028FF48 Val int: 2686824 Val char: 68
Bytes from str: +28 Ptr Addr: 0028FF4C Val int: 4198992 Val char: 50
Bytes from str: +32 Ptr Addr: 0028FF50 Val int: 1 Val char: 01
正如@Joe所说,使用va_*
宏来读取变量数参数。
否则,程序可能无法在某些环境中工作 - 例如,x86_64,其中参数在寄存器上传递,而不是在堆栈上传递。
我做了一些修改
并在Wandbox上运行代码。
Result变成了这样:
Bytes from str: -64 Ptr Addr: 0x7fff2308b498 Val int: -1473084125 Val char: 23
Bytes from str: -60 Ptr Addr: 0x7fff2308b49c Val int: 0 Val char: 00
Bytes from str: -56 Ptr Addr: 0x7fff2308b4a0 Val int: 4196088 Val char: F8
Bytes from str: -52 Ptr Addr: 0x7fff2308b4a4 Val int: 0 Val char: 00
Bytes from str: -48 Ptr Addr: 0x7fff2308b4a8 Val int: 35 Val char: 23
Bytes from str: -44 Ptr Addr: 0x7fff2308b4ac Val int: 0 Val char: 00
Bytes from str: -40 Ptr Addr: 0x7fff2308b4b0 Val int: -1473063104 Val char: 40
Bytes from str: -36 Ptr Addr: 0x7fff2308b4b4 Val int: 32682 Val char: AA
Bytes from str: -32 Ptr Addr: 0x7fff2308b4b8 Val int: -1470881080 Val char: C8
Bytes from str: -28 Ptr Addr: 0x7fff2308b4bc Val int: 32682 Val char: AA
Bytes from str: -24 Ptr Addr: 0x7fff2308b4c0 Val int: 0 Val char: 00
Bytes from str: -20 Ptr Addr: 0x7fff2308b4c4 Val int: 0 Val char: 00
Bytes from str: -16 Ptr Addr: 0x7fff2308b4c8 Val int: 4195810 Val char: E2
Bytes from str: -12 Ptr Addr: 0x7fff2308b4cc Val int: 0 Val char: 00
Bytes from str: -08 Ptr Addr: 0x7fff2308b4d0 Val int: 0 Val char: 00
Bytes from str: -04 Ptr Addr: 0x7fff2308b4d4 Val int: 0 Val char: 00
Bytes from str: +00 Ptr Addr: 0x7fff2308b4d8 Val int: 4196155 Val char: 3B
Bytes from str: +04 Ptr Addr: 0x7fff2308b4dc Val int: 0 Val char: 00
Bytes from str: +08 Ptr Addr: 0x7fff2308b4e0 Val int: 587773152 Val char: E0
Bytes from str: +12 Ptr Addr: 0x7fff2308b4e4 Val int: 32767 Val char: FF
Bytes from str: +16 Ptr Addr: 0x7fff2308b4e8 Val int: -1477724000 Val char: A0
Bytes from str: +20 Ptr Addr: 0x7fff2308b4ec Val int: 5 Val char: 05
Bytes from str: +24 Ptr Addr: 0x7fff2308b4f0 Val int: -1475311104 Val char: 00
Bytes from str: +28 Ptr Addr: 0x7fff2308b4f4 Val int: 32682 Val char: AA
Bytes from str: +32 Ptr Addr: 0x7fff2308b4f8 Val int: 1111 Val char: 57
Bytes from str: +36 Ptr Addr: 0x7fff2308b4fc Val int: 0 Val char: 00
Bytes from str: +40 Ptr Addr: 0x7fff2308b500 Val int: 2222 Val char: AE
Bytes from str: +44 Ptr Addr: 0x7fff2308b504 Val int: 0 Val char: 00
Bytes from str: +48 Ptr Addr: 0x7fff2308b508 Val int: 3333 Val char: 05
Bytes from str: +52 Ptr Addr: 0x7fff2308b50c Val int: 0 Val char: 00
Bytes from str: +56 Ptr Addr: 0x7fff2308b510 Val int: 4196064 Val char: E0
Bytes from str: +60 Ptr Addr: 0x7fff2308b514 Val int: 0 Val char: 00
Bytes from str: +64 Ptr Addr: 0x7fff2308b518 Val int: -1473063104 Val char: 40
pointer passed = 4196155 0x40073b
如您所见,值在Bytes from str: +00
上作为指针传递,但其他参数的值不在该值附近。