简体   繁体   中英

Using cgo, why does C output not 'survive' piping when golang's does?

I'm experimenting with cgo to use C code from golang, but in my little hello-world test, I've ran into something I can't understand or find more information about.

I'm starting with a simple test similar to examples I've found

    package main

    import (
        "fmt"
        "unsafe"
    )

    /*
    #import <stdio.h>
    #import <stdlib.h>
    */
    import "C"

    func main() {
        go2c := "Printed from C.puts"
        var cstr *C.char = C.CString(go2c)
        defer C.free(unsafe.Pointer(cstr))
        C.puts(cstr)
        fmt.Printf("Printed from golang fmt\n")
    }

This simple example just echoes strings to stdout from both golang (using fmt.Printf ) and raw C (using C.puts ) via the basic cgo binding.

When I run this directly in my terminal, I see both lines:

    $ ./main
    Printed from C.puts
    Printed from golang fmt

When I run this but redirect output in any way – pipe to less , shell redirection to a file, etc – I only see golang's output:

    ./main | cat
    Printed from golang fmt

What happens to the C.puts content when piping / redirecting?

Secondary questions: Is this a cgo quirk, or ac standard library quirk I'm not aware of? Is this behaviour documented? How would I go about debugging this on my own (eg is there a good/plausible way for me to 'inspect' what FD1 really is in each block?)

Update: If it's relevant, I'm using go version go1.6.2 darwin/amd64 .

This is C behavior you're seeing.

Go does not buffer stdout , while in C it is usually buffered. When the C library detects stdout is a tty, it may use line buffering, so the additional \\n inserted by puts will cause the output to be displayed.

You need to flush stdout to ensure you get all the output:

go2c := "Printed from C.puts"
var cstr *C.char = C.CString(go2c)
defer C.free(unsafe.Pointer(cstr))
C.puts(cstr)
C.fflush(C.stdout)
fmt.Printf("Printed from golang fmt\n")

See also

Why does printf not flush after the call unless a newline is in the format string?

Is stdout line buffered, unbuffered or indeterminate by default?

The C library buffering is per line, so the first line can be left in the buffer before it is properly flushed (done at exit time in C programs). You can either try to flush stdout, or try adding a trailing \\n in the first string. Does it work if you add the \\n?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM