英文:
Using cgo, why does C output not 'survive' piping when golang's does?
问题
我正在使用cgo来从golang中使用C代码进行实验,但在我的小型hello-world测试中,我遇到了一些我无法理解或找到更多信息的问题。
我从一个类似于我找到的示例开始进行简单的测试(https://github.com/draffensperger/go-interlang/blob/master/go_to_c/c_in_comment/main.go)
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")
}
这个简单的示例通过基本的cgo绑定,从golang(使用fmt.Printf)和原始的C(使用C.puts)将字符串回显到stdout。
当我直接在终端中运行时,我可以看到两行输出:
$ ./main
Printed from C.puts
Printed from golang fmt
但是,当我运行这个程序并将输出重定向到其他地方,比如通过管道到less,或者通过shell重定向到文件等等,我只能看到golang的输出:
./main | cat
Printed from golang fmt
当进行管道/重定向时,C.puts的内容会发生什么变化?
附加问题:这是cgo的一个怪异行为,还是我不知道的C标准库的怪异行为?这种行为是否有文档记录?我该如何自行调试(例如,是否有一种好的/可行的方法让我在每个块中“检查”FD1是什么)?
更新:如果相关的话,我正在使用go version go1.6.2 darwin/amd64。
英文:
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 a c standard library quirk I'm not aware of? Is this behaviour documented? How would I go about debugging this on my own (e.g. 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.
答案1
得分: 3
这是你所看到的 C 语言行为。
Go 语言不会缓冲 stdout,而在 C 语言中通常会进行缓冲。当 C 库检测到 stdout 是终端时,它可能会使用行缓冲,因此 puts 插入的额外 \n 会导致输出被显示出来。
你需要刷新 stdout 以确保获取所有的输出:
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")
参考资料:
英文:
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
答案2
得分: 1
C库的缓冲是按行进行的,因此在正确刷新之前(在C程序退出时完成),第一行可以保留在缓冲区中。你可以尝试刷新stdout,或者在第一个字符串中添加一个尾随的\n。如果添加\n后能正常工作吗?
英文:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论