Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. Cast down
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Sweden
    Posts
    321
    Rep Power
    12

    Why does printf take parms in backwards?


    printf("%c %c %c", fgetc(fp), fgetc(fp), fgetc(fp));
    for example, would output "E X #" if the file has "#XE", why is that?
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,155
    Rep Power
    2222
    Oh darn it! My Petzold is at work! So I'll have to do this one from memory.

    C and Pascal pass arguments in different order. Pascal starts with the first one and works its way to the right, whereas C starts with the last one as works its way to the left. For the most part, this is strictly an implementation detail that is completely transparent to the programmer because the function body handles the order correctly.

    However, it does become an issue when an external function is written in a different language. I believe that it was for this reason that Windows programming (Win16; I assume also for Win32) picked the PASCAL convention. I'm sure that it was in the Petzold Windows 3.1 book where he explained that for the declaration of either the main function or the WndProc or both.

    However, I would have thought that the compilers would have been written to handle your situation properly. What compiler and OS did you run that line on when you got the problem? I'll throw my own test program together some time today and see what I get.

    BTW, here's a story that shows that compilers don't always give us what we expect. In our Java class, the instructor gave us one of those expression that we should never write, but he had first tested it in C and was surprised when Java gave him a different result (the correct one); in C:
    Code:
    int main(void)
    {
        int x, y;
    
        x = 3;
        y = x + x * ++x;
        printf("x=%d; y=%d\n",x,y);
    
        return 0;
    }
    I tested it in various languages (C (both a DOS program generated with Visual C++ v1.52 and gcc on Linux), Perl, and AWK, Java, Javascript, and PocketC for the Palm).

    The correct evaluation would have been: 3 + 3 * 4 = 15. Which is what we obtained from the stack-oriented languages (Java, Javascript, and PocketC). But C (on Intel), perl, and awk all came up with the answer, 20. That is because they all generated native Intel code that did the ++ first, which changed the value in x's memory location, then they pulled x's value out of that memory location throughout the rest of the evaluation (I verified this by view the assembly that C generated).

    My conclusion was that C code written on different platforms can possibly yield different results.
  4. #3
  5. No Profile Picture
    status unknown
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Posts
    262
    Rep Power
    12
    Originally posted by dwise1_aol
    C and Pascal pass arguments in different order. Pascal starts with the first one and works its way to the right, whereas C starts with the last one as works its way to the left.
    No, this is incorrect. The order of evaluation of function arguments in C (and C++) is unspecified. Your compiler is free to evaluate them left to right, right to left, or some other chosen sequence. Not only that, but it can choose a different order for subsequent execution of the same code.
  6. #4
  7. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    yea but parameters area always pushed onto the stack from right to left, isnt that why?
  8. #5
  9. No Profile Picture
    status unknown
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Posts
    262
    Rep Power
    12
    Originally posted by dwise1_aol
    BTW, here's a story that shows that compilers don't always give us what we expect. In our Java class, the instructor gave us one of those expression that we should never write, but he had first tested it in C and was surprised when Java gave him a different result (the correct one); in C:
    Code:
    int main(void)
    {
        int x, y;
    
        x = 3;
        y = x + x * ++x;
        printf("x=%d; y=%d\n",x,y);
    
        return 0;
    }
    I tested it in various languages (C (both a DOS program generated with Visual C++ v1.52 and gcc on Linux), Perl, and AWK, Java, Javascript, and PocketC for the Palm).

    The correct evaluation would have been: 3 + 3 * 4 = 15. Which is what we obtained from the stack-oriented languages (Java, Javascript, and PocketC). But C (on Intel), perl, and awk all came up with the answer, 20. That is because they all generated native Intel code that did the ++ first, which changed the value in x's memory location, then they pulled x's value out of that memory location throughout the rest of the evaluation (I verified this by view the assembly that C generated).

    My conclusion was that C code written on different platforms can possibly yield different results.
    I'm curious. Why do you believe that the "correct" answer is 3 + 3 * 4 = 15?

    If we add parentheses to show the precedence of the operators involved, for C and C++, I believe it should be:

    y = (x + (x * (++x)));

    ++ has higher precedence than * or +. * has higher precedence than +. If this is the case we should get:

    y = x + (x * (4));
    y = x + (4 * 4);
    y = x + 16;
    y = 4 + 16 = 20.
  10. #6
  11. No Profile Picture
    status unknown
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Posts
    262
    Rep Power
    12
    Originally posted by infamous41md
    yea but parameters area always pushed onto the stack from right to left, isnt that why?
    No, it's not why. The order that parameters are pushed onto the stack, even if that happens to be right to left, is irrelevant. As I said, in C and in C++ the order in which they are *evaluated* is unspecified. Compilers are free to choose the order of evaluation. It varies between compilers. Some evaluate from left to right.
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,155
    Rep Power
    2222
    Originally posted by BigBadBob
    I'm curious. Why do you believe that the "correct" answer is 3 + 3 * 4 = 15?

    If we add parentheses to show the precedence of the operators involved, for C and C++, I believe it should be:

    y = (x + (x * (++x)));

    ++ has higher precedence than * or +. * has higher precedence than +. If this is the case we should get:

    y = x + (x * (4));
    y = x + (4 * 4);
    y = x + 16;
    y = 4 + 16 = 20.
    Taking the infix expression y = x + x * ++x and running it through the shunting algorithm yields the postfix (AKA "reverse Polish") expression: y x x x ++ * + =. As I was taught, postfix expressions are evaluated on a stack (actually, programming that assignment was my first program that compiled successfully and ran correctly on the very first try -- and in PL/I at that). After all, evaluation is from left to right. The values of x will have been pushed onto the stack before the ++ operator changes x in memory and the x on the top of the stack. I have about 20 lines of text describing the calculation step-by-step; I'll assume that nobody wants to see it posted here.

    I guess it all boils down to our interpretation of whether evaluating from left to right means that all the preceding values of x should be affected by an operation on the last instance of x or not. I vote for fetching x's values before the ++, whereas you apparently vote for fetching them afterwards.

    But what's more important is that we have two different sets of languages that disagree on this point. Furthermore, the same language, C (and possibly perl and awk too), will end up disagreeing with itself depending on whether it's running on a stack-oriented machine or not.

    The real bottom line is to become aware of possible differences of interpretation between your compiler and yourself and to write your code to tell the compiler unambiguously and precisely what you want it to do. Code like that example should never be written unless you know exactly how your compiler is going to implement it.
  14. #8
  15. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,155
    Rep Power
    2222
    Originally posted by BigBadBob
    No, this is incorrect. The order of evaluation of function arguments in C (and C++) is unspecified. Your compiler is free to evaluate them left to right, right to left, or some other chosen sequence. Not only that, but it can choose a different order for subsequent execution of the same code.
    No, Pascal and C do have different calling conventions and that was an issue in Win16 where we needed to specify the Pascal calling convention, but apparently now it has been replaced by the WINAPI macro; from the Visual C++ 6 help:
    Obsolete Calling Conventions
    Home | Overview | How Do I

    The __pascal, __fortran, and __syscall calling conventions are no longer supported. You can emulate their functionality by using one of the supported calling conventions and appropriate linker options.

    WINDOWS.H now supports the WINAPI macro, which translates to the appropriate calling convention for the target. Use WINAPI where you previously used PASCAL or __far __pascal.
    So my memory does serve me correctly regarding the need to use the PASCAL manifest/macro. Also, MSDN describes the calling convention used by Windows (http://msdn.microsoft.com/library/de.../vxds_671u.asp) -- I added the bolding:
    Windows Calling Conventions
    This documentation presents the syntax of most functions in C-language notation. All such functions are assumed to be declared as FAR PASCAL functions, and Windows will call these functions as such. In general, exported functions in a device driver must execute the standard Windows prolog on entry and epilog on exit.

    The following list highlights the calling conventions:

    Set the DS register to the selector of the driver's automatic data segment.
    Save and restore the following registers if used: SS, SP, BP, SI, DI, and DS.
    Clear the direction flag if it has been set or modified.
    Place 16-bit return values in the AX register; 32-bit values in the DX:AX register pair.
    Execute a FAR return.
    Windows pushes all parameters on the stack in a left to right order (the last parameter shown in the function syntax is closest to the stack pointer). Windows also passes pointer parameters as 32-bit quantities, pushing the selector first then the offset. This allows exported functions to use the lds or les instructions to retrieve pointers from the stack.
    Now, I most certainly agree that movEAX_444's compiler should have evaluated the arguments from left to right before using whatever calling convention to pass them to the function. That is why I asked to know what compiler he was using and on what OS. Certainly, as per our discussion on that ambiguous expression that is evaluated differently by different languages and OSes, this should be an indication to movEAX_444 that his compiler is not doing what he expects and wants, so he should modify his code to get what he does want.

    But I would still like to know what his compiler and OS are.
    Last edited by dwise1_aol; August 30th, 2003 at 04:54 PM.
  16. #9
  17. Cast down
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jul 2003
    Location
    Sweden
    Posts
    321
    Rep Power
    12
    I see. Thanks.

    MS Visual C++ .NET on XP
  18. #10
  19. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,155
    Rep Power
    2222
    Originally posted by movEAX_444
    I see. Thanks.

    MS Visual C++ .NET on XP
    I'll also see whether gcc and Visual C++ 1.52 & 6.0 do the same thing. Probably won't be able to get to it and post my results until tonight (ie, in about six hours).
  20. #11
  21. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    running this on gcc
    Code:
    printf("%c %c %c %c\n", fgetc(fp), fgetc(fp), fgetc(fp), fgetc(fp));
    on a file that reads ABCD yields DCBA, same as on VC++.
  22. #12
  23. No Profile Picture
    status unknown
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2003
    Posts
    262
    Rep Power
    12
    I have no idea why you keep talking about the order things are pushed onto the stack. It has absolutely no relevance to the original question whatsoever. You seem to have completely missed the point.

    You can place the arguments onto the stack in any order you like, it makes no difference. The issue is which order they're evaluated.

    C and C++ both have international standards that state clearly that the order of evaluation of function arguments is unspecified. It can occur in any order. Any compiler, on any OS, can implement this in any order it chooses, whether it be left to right, right to left, or some other chosen sequence.

    This has nothing to do with the calling convention that you're talking about, which is effectively just a protocol for storing and accessing the parameters on the stack. Please understand the difference between placing the parameters on the stack, and evaluating them.

    C and C++ are not defined by Microsoft, via MSDN, but by the international standards. It's foolhardy to quote MSDN as a definitive source. It's a specific implementation. Even if VC++ was fully conforming to the standard, which it isn't, it would still be a specific implementation and will do certain things in an implementation specific way. It would be like looking up the range of signed int on MSDN and claiming that it's the representation of signed int in C or C++.

    The observation made in the original question is due to the order of evaluation of the arguments, *not* the calling convention used.
  24. #13
  25. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    hi, obviously you know a lot more about C then i do. so perhaps you could explain this to me. The original question was why do the letters get printed out backwards. The answer seems fairly simple to me, but your saying its irrelevant. here is an example:
    Code:
    <:oo7:> cat test.c 
    #include <stdio.h>
    #include <fcntl.h>
    
    FILE *fp;
    
    char foo1(){    return fgetc(fp);       }
    char foo2(){    return fgetc(fp);       }
    char foo3(){    return fgetc(fp);       }
    
    main()
    {
            fp = fopen("./foo", "r");
            printf("%c %c %c\n", foo1(), foo2(), foo3()); 
    }
    when disassembled, that yields:
    Code:
    Dump of assembler code for function main:
    0x80483fc <main>:       push   %ebp
    0x80483fd <main+1>:     mov    %esp,%ebp
    0x80483ff <main+3>:     sub    $0x8,%esp
    0x8048402 <main+6>:     and    $0xfffffff0,%esp
    0x8048405 <main+9>:     mov    $0x0,%eax
    0x804840a <main+14>:    sub    %eax,%esp
    0x804840c <main+16>:    sub    $0x8,%esp
    0x804840f <main+19>:    push   $0x80484a4
    0x8048414 <main+24>:    push   $0x80484a6
    0x8048419 <main+29>:    call   0x80482e8 <fopen>
    0x804841e <main+34>:    add    $0x10,%esp
    0x8048421 <main+37>:    mov    %eax,0x80495c8
    0x8048426 <main+42>:    call   0x80483e0 <foo3>//here the character 'A' is returned
    0x804842b <main+47>:    movsbl %al,%eax
    0x804842e <main+50>:    push   %eax //the rightmost argument to printf is pushed, 'A'
    0x804842f <main+51>:    sub    $0xc,%esp
    0x8048432 <main+54>:    call   0x80483c4 <foo2>//now 'B' is returned
    0x8048437 <main+59>:    add    $0xc,%esp
    0x804843a <main+62>:    movsbl %al,%eax
    0x804843d <main+65>:    push   %eax //next arg to printf is pushed, 'B'
    0x804843e <main+66>:    sub    $0x8,%esp
    0x8048441 <main+69>:    call   0x80483a8 <foo1>//now 'C' is returned
    0x8048446 <main+74>:    add    $0x8,%esp
    0x8048449 <main+77>:    movsbl %al,%eax
    0x804844c <main+80>:    push   %eax //next arg from right to printf is pushed, 'C'
    0x804844d <main+81>:    push   $0x80484ac //the address of the format string is pushed
    0x8048452 <main+86>:    call   0x80482d8 <printf>
    0x8048457 <main+91>:    add    $0x10,%esp
    0x804845a <main+94>:    leave  
    0x804845b <main+95>:    ret
    so now you have this: printf("%c %c %c\n", C, B, A);

    yes? or have i completely missed the point and gone on some irrelevant tangent?
  26. #14
  27. not a fan of fascism (n00b)
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Feb 2003
    Location
    ct
    Posts
    2,756
    Rep Power
    95
    i was thinking, and if your on windows, perhaps you could redeclare printf as a _fastcall so it passes the arguments thru the registers instead. maybe that might change whats going on?
  28. #15
  29. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Aug 2003
    Posts
    54
    Rep Power
    11
    It's irrelevant because there is no solution that will apply to all compilers.

    No matter how you hack your way around it, it will still be a hack. The C standard does not define any argument evaluation order, so whatever works on your compiler may work completely differently on another. If it's necessary that your arguments be evaluated in a certain order, it should be done before the function call.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo