参数在C中用省略号传递

时间:2016-03-04 08:14:16

标签: c stack ellipsis

我需要在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;我的实现中的库。

3 个答案:

答案 0 :(得分:5)

您正在尝试编写可变参数(有时称为varargs)函数。幸运的是,有标准的C库函数可以帮助您管理已经在堆栈上传递的参数。

您需要va_start va_endva_nextva_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上作为指针传递,但其他参数的值不在该值附近。