英文:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论