【问题标题】:Using cgo, why does C output not 'survive' piping when golang's does?使用 cgo,为什么当 golang 输出时 C 输出不能“生存”管道?
【发布时间】:2017-03-07 05:51:24
【问题描述】:

我正在尝试使用 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

当我运行这个但以任何方式 redirect 输出时——管道到less、shell 重定向到文件等——我只看到 golang 的输出:

    ./main | cat
    Printed from golang fmt

管道/重定向时C.puts 内容会发生什么情况?

次要问题:这是一个 cgo 怪癖,还是我不知道的 c 标准库怪癖?这种行为是否记录在案?我将如何自行调试(例如,我是否有一种好的/合理的方法来“检查”每个块中的 FD1 到底是什么?)

更新:如果相关,我正在使用go version go1.6.2 darwin/amd64

【问题讨论】:

    标签: go cgo


    【解决方案1】:

    这是您看到的 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?

    【讨论】:

    • 谢谢 - 我偶然发现需要在发布后立即刷新:-)。我不完全理解 为什么 c 在这种情况下会缓冲,与“正常”c 相比:如果我直接使用 puts 编写等效的 hello-world C 程序并重定向它,我按预期查看输出。在那种情况下,我的 C 编译器是为我添加了刷新还是什么?
    • 做了一些研究; C 通常会在终止时刷新,但 cgo 不会调用 C 的 atexit 回调 - 问题 #4221 表明这是故意的,但 other issues 让它模棱两可。显然是been discussed,但我找不到那个讨论。 fflush 就是这样!
    • @orls:是的,这是有道理的。我一直认为,如果您需要确保数据已写入,请无论如何调用 fflush。
    【解决方案2】:

    C 库缓冲是每行的,因此第一行可以在正确刷新之前留在缓冲区中(在 C 程序的退出时完成)。您可以尝试刷新标准输出,或尝试在第一个字符串中添加尾随 \n。如果添加\n,它会起作用吗?

    【讨论】:

    • 哈,刚发帖就发现了,正准备自己回答,结果你先来了!否:添加换行符没有区别(puts 无论如何都会添加一个)。但是::刷新标准输出会有所不同:C.fflush(C.stdout) 在相关点起作用
    猜你喜欢
    • 1970-01-01
    • 2011-06-12
    • 2022-01-08
    • 2010-12-07
    • 1970-01-01
    • 1970-01-01
    • 2018-04-21
    • 2014-09-21
    • 1970-01-01
    相关资源
    最近更新 更多