C 写调用和 Go 之间的差异 syscall.Write
Differences between C write call and Go syscall.Write
syscall write
returns -1 并设置 errno
是一个微不足道的案例。如果 C write
调用返回零或正数,我对 errno
的状态感兴趣。 Go 中的包装器 syscall.Write
只是 returns err
如果 errno
在任何情况下都不为零,这也包括 write
调用 returns 的情况阳性。
然而,man page of C write
call大致描述errno
也可能设置但未指定,如果我们写入零长度缓冲区而不解释任何细节。
因此,以下情况似乎不清楚:
- 如果
write
调用为文件、非阻塞套接字或阻塞套接字返回 0,errno
的状态是什么?
- 何时以及如何
write
调用返回 0 而 errno
不是 0?
- 如果
write
调用返回正数,errno
的状态是什么?会不会是负数?
- 有没有其他系统调用可能遇到同样的情况?
我认为上面的描述指出了 C write
调用和 Go syscall.Write
之间的区别,这对开发人员来说不清楚,这里是我的想法:
根据手册页,C write
对文件和非阻塞套接字的调用明确定义了返回零,但不清楚是否存在阻塞套接字的非错误条件导致 write()
不阻塞,返回 0,并且(大概)如果重试可能稍后会成功。
确实 Go 直接包装了系统调用 write
。但是,下面的代码片段似乎并不安全,因为 written
等于零是可能触发 err
的情况,但我们不想打破循环:
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
}
我的怀疑有错吗?
对于write
,只有两种情况需要考虑:
- 如果失败,则结果为-1,并设置
errno
。
- 如果成功,则结果为 0 或更大,并且
errno
未设置。
没有其他情况需要考虑,除非您对历史 Unix 实现感兴趣(参见:Is a return value of 0 from write(2) in C an error?)。
write
可能return0的原因是输入缓冲区可能为空。
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 长度写入可能会失败。如果失败,它 returns -1 并设置 errno
。如果成功,它 returns 0 并且不设置 errno
。这与任何其他写入的行为相同,它只是在手册页中提到,因为人们可能会惊讶于 0 长度写入可能会失败。
What is the status of errno
if write
call returning 0 for a file, a non-blocking socket, or a blocking socket?
在这种情况下,errno
没有设置,因为write
没有失败。只有当输入缓冲区为零字节时才会发生这种情况。
When and how write
call returning 0 and errno
is not 0?
这不会发生。 errno
已设置且 return 为 -1,或者 errno
未设置且 return 为 0 或更大。
What is the status of errno
if write
call returning positive? Will it be negative?
errno
值将不会被设置。它将具有与 write
调用之前相同的值。
Is there any other syscall may encounter the same situation?
一般来说,系统调用会return一个错误或者它们会成功。他们不会做两者的混合。查看其他手册页的 Return 值部分,您会发现它们大部分与 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
}
注意有点多余,我们可以这样做:
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(好吧,直到你进入内核)。
手册页显示了 C 存根 write
的调用约定和行为。 Go 选择在自己的存根 syscall.Write
中复制该行为。实际系统调用本身只有汇编语言接口。
syscall write
returns -1 并设置 errno
是一个微不足道的案例。如果 C write
调用返回零或正数,我对 errno
的状态感兴趣。 Go 中的包装器 syscall.Write
只是 returns err
如果 errno
在任何情况下都不为零,这也包括 write
调用 returns 的情况阳性。
然而,man page of C write
call大致描述errno
也可能设置但未指定,如果我们写入零长度缓冲区而不解释任何细节。
因此,以下情况似乎不清楚:
- 如果
write
调用为文件、非阻塞套接字或阻塞套接字返回 0,errno
的状态是什么? - 何时以及如何
write
调用返回 0 而errno
不是 0? - 如果
write
调用返回正数,errno
的状态是什么?会不会是负数? - 有没有其他系统调用可能遇到同样的情况?
我认为上面的描述指出了 C write
调用和 Go syscall.Write
之间的区别,这对开发人员来说不清楚,这里是我的想法:
根据手册页,C write
对文件和非阻塞套接字的调用明确定义了返回零,但不清楚是否存在阻塞套接字的非错误条件导致 write()
不阻塞,返回 0,并且(大概)如果重试可能稍后会成功。
确实 Go 直接包装了系统调用 write
。但是,下面的代码片段似乎并不安全,因为 written
等于零是可能触发 err
的情况,但我们不想打破循环:
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
}
我的怀疑有错吗?
对于write
,只有两种情况需要考虑:
- 如果失败,则结果为-1,并设置
errno
。 - 如果成功,则结果为 0 或更大,并且
errno
未设置。
没有其他情况需要考虑,除非您对历史 Unix 实现感兴趣(参见:Is a return value of 0 from write(2) in C an error?)。
write
可能return0的原因是输入缓冲区可能为空。
However, the man page of C
write
call roughly describeserrno
may also be set but unspecified if we write zero length buffer without explaining any detail.
这意味着 0 长度写入可能会失败。如果失败,它 returns -1 并设置 errno
。如果成功,它 returns 0 并且不设置 errno
。这与任何其他写入的行为相同,它只是在手册页中提到,因为人们可能会惊讶于 0 长度写入可能会失败。
What is the status of
errno
ifwrite
call returning 0 for a file, a non-blocking socket, or a blocking socket?
在这种情况下,errno
没有设置,因为write
没有失败。只有当输入缓冲区为零字节时才会发生这种情况。
When and how
write
call returning 0 anderrno
is not 0?
这不会发生。 errno
已设置且 return 为 -1,或者 errno
未设置且 return 为 0 或更大。
What is the status of
errno
ifwrite
call returning positive? Will it be negative?
errno
值将不会被设置。它将具有与 write
调用之前相同的值。
Is there any other syscall may encounter the same situation?
一般来说,系统调用会return一个错误或者它们会成功。他们不会做两者的混合。查看其他手册页的 Return 值部分,您会发现它们大部分与 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
}
注意有点多余,我们可以这样做:
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(好吧,直到你进入内核)。
手册页显示了 C 存根 write
的调用约定和行为。 Go 选择在自己的存根 syscall.Write
中复制该行为。实际系统调用本身只有汇编语言接口。