My error or fprintf implementation error ?

Discussion in 'C Programming' started by Jos De Laender, Aug 14, 2003.

  1. 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
     
    Jos De Laender, Aug 14, 2003
    #1
    1. Advertising

  2. Jos De Laender

    -berlin.de Guest

    Jos De Laender <> wrote:
    > 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
    --
    _ _____ _____
    | ||_ _||_ _| -berlin.de
    _ | | | | | |
    | |_| | | | | | http://www.physik.fu-berlin.de/~toerring
    \___/ens|_|homs|_|oerring
     
    -berlin.de, Aug 14, 2003
    #2
    1. Advertising

  3. Jos De Laender

    Ben Pfaff Guest

    Jos De Laender <> writes:

    > 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.
    --
    "Large amounts of money tend to quench any scruples I might be having."
    -- Stephan Wilms
     
    Ben Pfaff, Aug 14, 2003
    #3
  4. Jos De Laender

    jacob navia Guest


    > 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
     
    jacob navia, Aug 14, 2003
    #4
  5. Eric Sosman wrote:
    >
    > Jos De Laender wrote:
    > > [...]
    > > > > 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

    >
    > In addition to the two approaches you mention (and the
    > above hackish elaboration on the first of them, which I
    > really don't recommend), there's the possibility of making
    > the caller of Convert() responsible for managing the buffer.
    > That is, instead of having Convert() provide the static or
    > dynamic memory to hold the result, ask the caller to provide
    > it and let Convert() simply fill it in. Then it's the
    > caller's responsibility to provide different buffers for
    > "contemporaneous" calls, to clean up dynamic allocations,
    > and so on.
    >
    > --
    >
     
    Jos De Laender, Aug 14, 2003
    #5
  6. Jos De Laender

    CBFalconer Guest

    Jos De Laender wrote:
    > -berlin.de wrote:
    > > Jos De Laender <> wrote:
    > >
    > > > 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

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Aug 15, 2003
    #6
  7. Jos De Laender

    CBFalconer Guest

    Eric Sosman wrote:
    > Jos De Laender wrote:
    >
    > > [...]

    >
    > 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.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Aug 15, 2003
    #7
  8. Jos De Laender

    CBFalconer Guest

    Jos De Laender wrote:
    > Eric Sosman wrote:
    > > Jos De Laender wrote:
    > >

    .... snip ...
    > >
    > > 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?)

    >
    > 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.

    --
    Chuck F () ()
    Available for consulting/temporary embedded and systems.
    <http://cbfalconer.home.att.net> USE worldnet address!
     
    CBFalconer, Aug 15, 2003
    #8
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Arti Potnis
    Replies:
    2
    Views:
    6,717
    Howard
    Sep 2, 2004
  2. Koen
    Replies:
    1
    Views:
    590
    Victor Bazarov
    Oct 5, 2004
  3. Replies:
    2
    Views:
    438
    Barry Schwarz
    Jan 2, 2004
  4. google
    Replies:
    5
    Views:
    5,144
    Dan Pop
    Apr 13, 2004
  5. Joy2006
    Replies:
    2
    Views:
    492
    Jim Langston
    May 26, 2006
Loading...

Share This Page