cstackellipsis

Parameter passing with ellipsis in C


I need to implement my own printf function in C. However I am having trouble using the ellipsis ("...") feature with my function.

According to my textbook, the parameters passed to a function with an ellipsis should be located on the stack right above where the first parameter is stored. I can not find any of the the additional parameters I am passing on the stack. Here is the code I used to test my function and the output:

#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);
}

Here is the output of the myprintf function (a printout of the stack):

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:

From what I understand, the values 1111, 2222, and 3333 should be located somewhere in this stack printout. Where are these values going when I make the function call?

EDIT: I cannot use the "stdarg.h" library in my implementation.


Solution

  • Behavior of this program may not granteed by the specification, but for this experiment of searching argument from the stack, you have to move the pointer pointing at the argument instead of the pointer passed as the argument.

    #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;
    }
    

    Result in my local environment:

    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 
    

    As @Joe says, use va_* macro to read variable number arguments. Otherwise, the program may not work in some environment -- for example, x86_64 where arguments are passed on register, not on the stack.

    I made some modification

    and ran the code on Wandbox.

    Result became like this:

    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
    

    As you see, the valued passed as pointer on Bytes from str: +00, but value of the other arguments are not near the value.