使用 cgo,为什么 C 输出不是 'survive' 管道,而 golang 是?
Using cgo, why does C output not 'survive' piping when golang's does?
我正在尝试使用 cgo 来使用来自 golang 的 C 代码,但是在我的 hello-world 小测试中,我 运行 遇到了一些我无法理解或找不到更多信息的东西。
我从类似于 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")
}
这个简单的示例只是通过基本的 cgo
绑定将 golang(使用 fmt.Printf
)和原始 C(使用 C.puts
)中的字符串回显到标准输出。
当我直接在终端中 运行 时,我看到两行:
$ ./main
Printed from C.puts
Printed from golang fmt
当我 运行 this but redirect 以任何方式输出 – 管道到 less
,shell 重定向到文件等 –我只看到golang的输出:
./main | cat
Printed from golang fmt
管道/重定向时 C.puts
内容会怎样?
次要问题:这是 cgo 怪癖,还是我不知道的 c 标准库怪癖?这种行为是否记录在案?我将如何自己调试它(例如,是否有 good/plausible 方法让我 'inspect' 每个块中的 FD1 到底是什么?)
更新:如果相关,我正在使用 go version go1.6.2 darwin/amd64
。
C 库缓冲是按行进行的,因此第一行可以在正确刷新之前留在缓冲区中(在 C 程序退出时完成)。您可以尝试刷新标准输出,或尝试在第一个字符串中添加尾随 \n。添加\n是否有效?
这是您看到的 C 行为。
Go 没有缓冲 stdout
,而在 C 中通常有缓冲。当 C 库检测到 stdout
是一个 tty 时,它可能会使用行缓冲,因此由 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")
另见
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?
我正在尝试使用 cgo 来使用来自 golang 的 C 代码,但是在我的 hello-world 小测试中,我 运行 遇到了一些我无法理解或找不到更多信息的东西。
我从类似于 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")
}
这个简单的示例只是通过基本的 cgo
绑定将 golang(使用 fmt.Printf
)和原始 C(使用 C.puts
)中的字符串回显到标准输出。
当我直接在终端中 运行 时,我看到两行:
$ ./main
Printed from C.puts
Printed from golang fmt
当我 运行 this but redirect 以任何方式输出 – 管道到 less
,shell 重定向到文件等 –我只看到golang的输出:
./main | cat
Printed from golang fmt
管道/重定向时 C.puts
内容会怎样?
次要问题:这是 cgo 怪癖,还是我不知道的 c 标准库怪癖?这种行为是否记录在案?我将如何自己调试它(例如,是否有 good/plausible 方法让我 'inspect' 每个块中的 FD1 到底是什么?)
更新:如果相关,我正在使用 go version go1.6.2 darwin/amd64
。
C 库缓冲是按行进行的,因此第一行可以在正确刷新之前留在缓冲区中(在 C 程序退出时完成)。您可以尝试刷新标准输出,或尝试在第一个字符串中添加尾随 \n。添加\n是否有效?
这是您看到的 C 行为。
Go 没有缓冲 stdout
,而在 C 中通常有缓冲。当 C 库检测到 stdout
是一个 tty 时,它可能会使用行缓冲,因此由 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")
另见
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?