3

to make the question clear, I wrote some test code:

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

char *foo(int a) {
    printf("%d\n", a);
    static char string[2];
    string[0] = a > 0? '1' : '0';
    string[1] = '\0';
    return string;
}

int main(void) {
    printf("%s\t%s\n", foo(1), foo(0));
    return 0;
}

Running the code gives output like this:

0
1
1       1

I have two questions here: 1. Why is 0 printed before 1? in main's printf function, the second foo is executed before the first? Is this a defined behaviour or just by chance. 2. Why is the final output 1, 1? The expected result should be 1, 0.

zvisofer
  • 1,346
  • 18
  • 41
Xufeng
  • 6,452
  • 8
  • 24
  • 30
  • 3
    The order in which function arguments are evaluated is unspecified. – jscs Feb 08 '14 at 22:27
  • @Enrico Granata - he is asking about C, not C++ – Joseph Feb 08 '14 at 22:30
  • This would be a great opportunity to learn how to use a debugger to step through your code. Stepping through would probably make it very clear to you what's happening. – jscs Feb 08 '14 at 22:33
  • Actually I did. I used gdb but foo is only be stepped in once. I was so confused.. – Xufeng Feb 08 '14 at 22:34
  • Great! That does sound confusing indeed; I'm not sure what could've gone wrong there. – jscs Feb 08 '14 at 22:35
  • @Joseph: fair enough. However, I would be surprised if C had specified this given that C++ has not (valid C programs that rely on an order would break in C++ if that were the case) – Enrico Granata Feb 08 '14 at 22:38

3 Answers3

2

The order of argument evaluation is implementation-dependent - your compiler just happens to implement it that way

EDIT: as per your second question, you are using a static buffer. That means it is shared by both foo() calls - i.e. both foo() calls return the same pointer.

Given your evaluation order, first a 0 is written, then a 1 is written. By the time both foo() calls are done, and it's time to print the buffer, a 1 is in there - in both cases (buffer static == shared).

If you want to fix this, you can have the caller pass in a buffer and your function writes to that user-provided memory so it's unique for each call.

Enrico Granata
  • 3,303
  • 18
  • 25
0

In your example, whether foo(1) or foo(0) is called first is not defined in C. In your case foo(0) was called, setting the static string of foo to "0" and returning the address of the string. Then foo(1) was called, setting the string to "1". Then you print the string twice. No matter what, it will always be the same.

ooga
  • 15,423
  • 2
  • 20
  • 21
  • OK I understand so far. But do you also suggest that in printf, the two %s are replaced after all the arguments are evaluated? – Xufeng Feb 08 '14 at 22:33
  • They aren't replaced at all. The address of that string is one of the arguments to the `printf` function. The `printf` function scans that string and interprets further arguments accordingly. The two extra arguments that you pass in are the address of the static string in foo, so they are identical and the same string is printed. – ooga Feb 08 '14 at 22:35
  • So does the compiler evaluated the arguments first and then print out the whole string? Because if it evaluates the arguments on the fly while it is printing the string, the two %s should have different values – Xufeng Feb 08 '14 at 22:38
  • Arguments to a function are evaluated before the body of the function is executed. If you want lazy argument evaluation, you will need to start dealing in function pointers (and writing your own printf that works that way :-) – Enrico Granata Feb 08 '14 at 22:40
  • @Xufeng Yes. All argument expressions are evaluated *before* the function is called. – user3125367 Feb 08 '14 at 22:40
0

The order of evaluating the arguments is implementation defined:

After calling printf:

printf("%s\t%s\n", foo(1), foo(0));

It calls foo() firstly with 0 then 1. On each call the address of String is returned and stored in a variable. Since String is static the address doesn't change. After calls ends, it comes to printf to print the String content which is the last change happens to String (after calling foo(1)). The same address means the same value, means the output is:

0
1
1       1
rullof
  • 7,124
  • 6
  • 27
  • 36