C写调用和Go syscall.Write之间的区别 [英] Differences between C write call and Go syscall.Write

查看:41
本文介绍了C写调用和Go syscall.Write之间的区别的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

syscall write 返回-1,而设置 errno 的情况很简单.我对 errno 的状态感兴趣,如果C write 调用返回零或正数.如果 errno 在任何情况下都不为零,则Go中的包装器 syscall.Write 仅返回 err ,这还包括 write的情况.调用返回正值.

syscall write returns -1 and set errno is a trivial case. I am interested in the status of errno if C write call returning zero or positive. The wrapper syscall.Write in Go simply returns err if errno is not zero for any case, which also includes the case of write call returns positive.

https://github.com/golang/go/blob/3cb64ea39e0d71fe2af554cbf4e99d14bc08d41b/src/syscall/zsyscall_linux_386.go#L1007

但是, C write的手册页调用粗略地描述了 errno 也可以设置,但是如果我们写零长度缓冲区而不进行任何详细说明,则未指定.

However, the man page of C write call roughly describes errno may also be set but unspecified if we write zero length buffer without explaining any detail.

因此,以下情况似乎不清楚:

Thus, the following cases seem unclear:

  1. 如果 write 调用为文件,非阻塞套接字或阻塞套接字返回0,则 errno 的状态是什么?
  2. 何时以及如何 write 调用返回0并且 errno 不为0?
  3. 如果 write 调用返回正值, errno 的状态如何?会否定?
  4. 是否还有其他系统调用可能遇到相同的情况?
  1. What is the status of errno if write call returning 0 for a file, a non-blocking socket, or a blocking socket?
  2. When and how write call returning 0 and errno is not 0?
  3. What is the status of errno if write call returning positive? Will it be negative?
  4. Is there any other syscall may encounter the same situation?

我认为以上描述指出了C write 调用和Go syscall.Write 之间的区别,这对于开发人员来说尚不清楚,这是我的想法:

I think the above description points to the difference between C write call and Go syscall.Write, which is unclear for developers, here are my thoughts:

根据手册页,对于文件和非阻塞套接字,在C write 调用中明确定义了返回零,但是不清楚阻塞套接字是否存在非错误条件,即会导致 write()不会阻塞,返回0,并且(如果可能)如果重试,则可能会在以后成功.

According to the man page, returning zero is clearly defined in C write call for to files and for non-blocking sockets, but it's unclear whether there are non-error conditions for a blocking socket which would result in a write() not blocking, returning 0, and (presumably) possibly succeeding later if retried.

Indeed Go直接包装系统调用 write .但是,以下代码段似乎并不安全,因为书面等于零的情况可能会触发 err ,但我们不想打破循环:

Indeed Go directly wraps system call write. However, the following code snippet seems not safe because written equals to zero is a case that may trigger err but we don't want to break the loop:

func writeAll(fd int, buffer []byte) bool {
    length := len(buffer)
    for length > 0 {
        written, err := syscall.Write(fd, buffer)
        if err != nil { // here
            return false
        }
        length -= written
        buffer = buffer[written:]
    }
    return true
}

我的怀疑有什么不对吗?

Is there any wrong in my suspicion?

推荐答案

使用 write ,只有两种情况需要考虑:

With write, there are only two cases to consider:

  1. 如果失败,则结果为-1,并设置了 errno .
  2. 如果成功,则结果为0或更大,并且未设置 errno .

没有其他情况可以考虑,除非您对历史上的Unix实现感兴趣(请参阅:

There are no other cases to consider, unless you are interested in historical Unix implementations (see: Is a return value of 0 from write(2) in C an error?).

write 可能返回0的原因是因为输入缓冲区可能为空.

The reason that write may return 0 is because the input buffer may be empty.

但是,如果我们编写零长度缓冲区而不进行解释,则C write 调用的手册页大致描述了 errno 可以,但未指定任何细节.

However, the man page of C write call roughly describes errno may also be set but unspecified if we write zero length buffer without explaining any detail.

这意味着0长度的写入可能会失败.如果失败,则返回-1并设置 errno .如果成功,则返回0,并且不设置 errno .这与其他任何写入操作相同,只是在手册页中提到,因为人们可能会惊讶地发现长度为0的写入可能会失败.

All this means is that it's possible for a 0-length write to fail. If it fails, it returns -1 and sets errno. If it succeeds, it returns 0 and does not set errno. This is the same behavior for any other write, it's just mentioned in the man page because people may find it surprising that a 0-length write could fail.

如果 write 调用为文件,非阻塞套接字或阻塞套接字返回0,则 errno 的状态是什么?

What is the status of errno if write call returning 0 for a file, a non-blocking socket, or a blocking socket?

在这种情况下,未设置 errno ,因为 write 不会失败.仅当输入缓冲区为零字节时才会发生这种情况.

In this case, errno is not set, because write did not fail. This will only happen if the input buffer is zero bytes.

何时以及如何 write 调用返回0并且 errno 不为0?

When and how write call returning 0 and errno is not 0?

这不会发生.设置 errno 且返回值为-1,或者未设置 errno 且返回值为0或更大.

This does not happen. Either errno is set and the return is -1, or errno is not set and the return is 0 or larger.

如果 write 调用返回正值, errno 的状态如何?会否定的?

What is the status of errno if write call returning positive? Will it be negative?

不会设置 errno 值.它将具有与 write 调用之前相同的值.

The errno value will not be set. It will have the same value as it did before the write call.

是否还有其他系统调用可能遇到相同的情况?

Is there any other syscall may encounter the same situation?

通常,系统调用将返回错误,它们将成功.他们不会将两者混合在一起.查看其他手册页的返回值"部分,您将发现它们与 write 大致相同.

In general, system calls will either return an error or they will succeed. They won't do some mixture of both. Look at the Return Value section of other man pages and you will see that they are mostly the same as write.

此代码是安全的.

func writeAll(fd int, buffer []byte) bool {
    length := len(buffer)
    for length > 0 {
        written, err := syscall.Write(fd, buffer)
        if err != nil { // here
            return false
        }
        length -= written
        buffer = buffer[written:]
    }
    return true
}

请注意,这有点多余,我们可以这样做:

Note that it's a bit redundant, we can just do this:

func writeAll(fd int, buf []byte) bool {
    for len(buf) > 0 {
        n, err := syscall.Write(fd, buf)
        if err != nil {
            return false
        }
        buf = buf[n:]
    }
    return true
}

关于C的注释

从技术上讲, write 既是系统调用又是C函数(至少在许多系统上).但是,C函数只是一个调用系统调用的存根.Go不会调用此存根,它会直接调用系统调用,这意味着C不在这里(好吧,直到您进入内核为止).

A note about C

Technically, write is both a system call and a C function (at least on many systems). However, the C function is just a stub which invokes the system call. Go does not call this stub, it invokes the system call directly, which means that C is not involved here (well, not until you get into the kernel).

手册页显示了C存根的调用约定和行为,即 write .Go选择将其行为复制到自己的存根 syscall.Write 中.实际的系统调用本身仅具有汇编语言界面.

The man page shows the calling conventions and behavior of the C stub, write. Go chooses to copy that behavior in its own stub, syscall.Write. The actual system call itself only has an assembly language interface.

这篇关于C写调用和Go syscall.Write之间的区别的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆