syphilis has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

The C header file (mylib.h):
#include <stdio.h> void my_puts(FILE*);
The C file (mylib.c):
#include <stdio.h> void my_puts(FILE * stream) { fputs("hello from libmylib", stream); }
Now, build the library (libmylib.a):
C:\_32\C>gcc -c mylib.c C:\_32\C>ar cru libmylib.a mylib.o
The perl script that accesses the function in libmylib.a:
use warnings; use strict; use Inline C => Config => INC => '-IC:/_32/C', LIBS => '-LC:/_32/C -lmylib', BUILD_NOISY => 1; use Inline C => <<'EOC'; #include <mylib.h> void foo(FILE * x) { my_puts(x); fflush(x); } EOC $| = 1; for(1 .. 2) { foo(*stdout); print "\nhello from perl\n"; } for(1 .. 2) { foo(*stderr); print "\nhello from perl\n"; }
Ok ... so I've got this library (libmylib.a) that was built using mylib.h and mylib.c. For the purposes of this exercise, that (3rd party) library is to be considered non-modifiable. Of course, if it's doing something sinful, please let me know. And I've got an Inline::C script that's accessing the one and only function that's in libmylib.a

As it stands, the script outputs (on Win32, perl 5.8.8):
hello from libmylib hello from perl hello from libmylib hello from perl hello from libmylib hello from perl hello from libmylib hello from perl
That's all well and good, and the exact output I'm wanting to see. But if I comment out the line that turns the autoflush on I get the following garbled output:
hello from libmylib hello from perl hello from libmylibhello from libmylibhello from libmylib hello from perl hello from perl hello from perl
I simply do not see why the output should vary in any way, dependent upon whether autoflush is on or off. As I understand it, perl's autoflush will have no effect on the C buffers ... and, since the perl print() statements terminate with a "\n", autoflush should have no effect on the perl buffers either.

I guess I'm overlooking something ... but what ?

Cheers,
Rob

Replies are listed 'Best First'.
Re: Really, really suffering from buffering
by shmem (Chancellor) on Nov 19, 2007 at 14:11 UTC
    From the PUTS manual page:
    BUGS
    It is not advisable to mix calls to output functions from the stdio library with low-level calls to write() for the file descriptor associated with the same output stream; the results will be undefined and very probably not what you want.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
      It is not advisable to mix calls to output functions from the stdio library with low-level calls to write() for the file descriptor associated with the same output stream

      So ... there will be no problem if foo() and print() write to different streams. And if foo() and print() do need to write to the same stream then there's *nothing* I can do to ensure that the output will not be garbled. Is that what the above quote is telling me ?

      I'm just trying to get an understanding of what *can* and *can't* be done here. I know I can't use fputs() in XSubs (I've tried), but I had hoped it would be possible to have ab XSub safely and sanely call an external C library function that uses fputs().

      Thanks, shmem.

      Cheers,
      Rob
        It makes no difference whether you call fputs() from XS code or via a wrapper of an external library function - fputs() lives in the stdio implementation and does the same for both XS and library code.

        And since stdio has its own ideas about buffering, I guess the safest thing to do is calling fflush() as you did. All that with much handwaving, since I'm not proficient with C.

        I remember having read remarks and caveats wrt to stdio, and advice to use the PerlIO layer instead. Sorry for being too lazy to delve into docs/sources to bring up those bits... maybe another monk has them present? - thanks ;)

        --shmem

        _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                      /\_¯/(q    /
        ----------------------------  \__(m.====·.(_("always off the crowd"))."·
        ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Really, really suffering from buffering
by oha (Friar) on Nov 19, 2007 at 13:55 UTC
    you are assuming that perl buffers are the same of C ones, which is probably wrong.

    Oha