My error or fprintf implementation error ?

J

Jos De Laender

Following simple program :

#include <stdio.h>

char *Convert(int Arg) {
static char Buffer[128];
printf("Convert called for %d\n",Arg);
sprintf(Buffer,"%d",Arg);
printf("Convert about returning %s\n",Buffer);
return Buffer;
}

main() {
printf("%s %s\n",Convert(10),Convert(56));
}

Generates output :

[jos@krekel TestStaticString]$ ./a.out
Convert called for 56
Convert about returning 56
Convert called for 10
Convert about returning 10
10 10

This is puzzling me a lot as I would expect 10 56

Can someone enlighten me on my error ?
I'm using gcc 2.96 on a Mandrake Linux system.

Thanks.

Jos
 
J

Jens.Toerring

Jos De Laender said:
Following simple program :
#include <stdio.h>
char *Convert(int Arg) {
static char Buffer[128];
printf("Convert called for %d\n",Arg);
sprintf(Buffer,"%d",Arg);
printf("Convert about returning %s\n",Buffer);
return Buffer;
}
main() {
printf("%s %s\n",Convert(10),Convert(56));
}
Generates output :
[jos@krekel TestStaticString]$ ./a.out
Convert called for 56
Convert about returning 56
Convert called for 10
Convert about returning 10
10 10
This is puzzling me a lot as I would expect 10 56

Sorry, but this is not an error of (f)printf(). When you call
it it receives three arguments. The first one is a pointer to
the format string, the second is the return value of a call of
Convert(10) and the third the return value of the call of
Convert(56). So both calls of Convert() are done *before*
printf() itself is invoked. But since both calls of Convert()
write into the same memory area, the static char array Buffer[],
the second call overwrites the result of the first call before
(f)printf() has a chance to print out the first result. You
can also see nicely that that the arguments to printf() aren't
necessarily evaluated left to right, any sequence the compiler
writers prefer is allowed and one should never rely on a certain
behavior.
Regards, Jens
--
_ _____ _____
| ||_ _||_ _| (e-mail address removed)-berlin.de
_ | | | | | |
| |_| | | | | | http://www.physik.fu-berlin.de/~toerring
\___/ens|_|homs|_|oerring
 
B

Ben Pfaff

Jos De Laender said:
char *Convert(int Arg) {
static char Buffer[128];
printf("Convert called for %d\n",Arg);
sprintf(Buffer,"%d",Arg);
printf("Convert about returning %s\n",Buffer);
return Buffer;
}

main() {
printf("%s %s\n",Convert(10),Convert(56));
}

There's only one static buffer. You can't use it twice and
expect it to magically have different two values at once.
 
J

jacob navia

Thanks. Sounds reasonable.

What would be a solution to avoid this ?
I can think of
X) Never calling it twice within printf , but that will go wrong one
day ...
X) Making a dynamic allocation instead of a static buffer. But then
deallocation must be systematically done for avoiding leaks ...
(cumbersome)

Other suggestions ?

Yes. Add an argument to that function: The buffer where it should print
the stuff.
No allocations, no problems
 
J

Jos De Laender

Eric said:
[...]
main() {
printf("%s %s\n",Convert(10),Convert(56));
}
[where Convert() fills in and returns a pointer to a static buffer]

What would be a solution to avoid this ?
I can think of
X) Never calling it twice within printf , but that will go wrong one
day ...
X) Making a dynamic allocation instead of a static buffer. But then
deallocation must be systematically done for avoiding leaks ...
(cumbersome)

I once implemented a similar function that had a small
array of static buffers and used them cyclically. That
let me call the function multiple times within a single
printf(), so long as I didn't call it more times than the
function had buffers. (Yes, Your Honor, I know it was wrong.
But I was in a hurry, and it was throw-away code, and I swear
I'll never do it again, and I throw myself on the mercy of
the Court. Aren't you up for re-electon soon?)

Hehe :)

Good suggestion after all.

My code will have thousands of those calls. So I'm really looking for a
solution where caller doesn't have to bother about buffers and cleanup.
And I know for sure - this is God told me in person :) - that there
will be no printf with more than 5 of those calls to Convert.

So thanks !

Jos
 
C

CBFalconer

Jos said:
Jos De Laender said:
Following simple program :
#include <stdio.h>
char *Convert(int Arg) {
static char Buffer[128];
printf("Convert called for %d\n",Arg);
sprintf(Buffer,"%d",Arg);
printf("Convert about returning %s\n",Buffer);
return Buffer;
}
main() {
printf("%s %s\n",Convert(10),Convert(56));
}
Generates output :
[jos@krekel TestStaticString]$ ./a.out
Convert called for 56
Convert about returning 56
Convert called for 10
Convert about returning 10
10 10
This is puzzling me a lot as I would expect 10 56

Sorry, but this is not an error of (f)printf(). When you call
it it receives three arguments. The first one is a pointer to
the format string, the second is the return value of a call of
Convert(10) and the third the return value of the call of
Convert(56). So both calls of Convert() are done *before*
printf() itself is invoked. But since both calls of Convert()
write into the same memory area, the static char array Buffer[],
the second call overwrites the result of the first call before
(f)printf() has a chance to print out the first result. You
can also see nicely that that the arguments to printf() aren't
necessarily evaluated left to right, any sequence the compiler
writers prefer is allowed and one should never rely on a certain
behavior.

Thanks. Sounds reasonable.

What would be a solution to avoid this ?
I can think of
X) Never calling it twice within printf , but that will go wrong one
day ...
X) Making a dynamic allocation instead of a static buffer. But then
deallocation must be systematically done for avoiding leaks ...
(cumbersome)

Other suggestions ?

Try:

int main(void) {
printf("%s ", Convert(10));
printf("%s\n", Convert(56));
return 0;
}

and now you know the sequence of calls to Convert.

Notice that main returns an int. Say and do so. The only int
values allowed are 0 or EXIT_SUCCESS or EXIT_FAILURE from stdlib.h
 
C

CBFalconer

Eric said:
Jos said:

I once implemented a similar function that had a small
array of static buffers and used them cyclically. That
let me call the function multiple times within a single
printf(), so long as I didn't call it more times than the
function had buffers. (Yes, Your Honor, I know it was wrong.
But I was in a hurry, and it was throw-away code, and I swear
I'll never do it again, and I throw myself on the mercy of
the Court. Aren't you up for re-electon soon?)

I have done the equivalent, and I don't consider it an evil
practice. In my case it served the purpose of supplying fixed
string arguments while keeping the strings in a separate
(editable) file and not using unavailable program memory space.
The implementation was via a special preprocessing run, so the
source looked totally normal.

Think of it as Garbage Collection, with a defined cycle time.
 
C

CBFalconer

Jos said:
Good suggestion after all.

My code will have thousands of those calls. So I'm really
looking for a solution where caller doesn't have to bother
about buffers and cleanup. And I know for sure - this is God
told me in person :) - that there will be no printf with more
than 5 of those calls to Convert.

You make convert auto initialize the buffers. Define a buffer as
a structure with a pointer to the next, and a pointer to the data
string. Keep a static pointer to a buffer. When convert is
called and finds that pointer NULL it knows it is initialization
time. It then creates a circular chained list of buffers, each of
which contains a different data pointer, which you get via
malloc. You control the number of buffers and size of the data
field here (God is fallible). Now the static pointer is no longer
NULL.

At each call to convert the static pointer is advanced via the
next field, and the data field is used as needed. Convert returns
the pointer to that data field.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top