C写调用和Go syscall.Write之间的区别
syscall write
返回-1,而set errno
是一个简单的情况。我对errno
C
write
调用返回零或正的状态感兴趣。该包装syscall.Write
在围棋简单的返回err
,如果errno
不是任何情况下,其中还包括的零的情况下write
调用返回正数。
https://github.com/golang/go/blob/3cb64ea39e0d71fe2af554cbf4e99d14bc08d41b/src/syscall/zsyscall_linux_386.go#L1007
然而,的C man页面write
调用大致介绍了errno
,如果我们写零长度的缓冲区没有解释任何细节也可以设置,但不确定。
因此,以下情况似乎不清楚:
errno
如果write
针对文件,非阻塞套接字或阻塞套接字的调用返回0 的状态是什么?- 什么时候以及如何
write
调用返回0而errno
不是0? errno
ifwrite
通话返回正数的状态如何?会否定的?- 还有其他系统调用可能会遇到相同的情况吗?
我认为以上描述指出了C write
call和Go 之间的区别syscall.Write
,这对于开发人员尚不清楚,这是我的想法:
根据手册页,在write
对文件和非阻塞套接字的C
调用中明确定义了返回零,但是尚不清楚阻塞套接字是否存在非错误条件,这将导致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实现感兴趣,否则没有其他情况可以考虑。
write
可能返回0 的原因是因为输入缓冲区可能为空。
然而,C的手册页
write
呼叫大致介绍了errno
,如果我们写零长度的缓冲区没有解释任何细节也可以设置,但不确定。
所有这一切意味着0长度写入可能会失败。如果失败,则返回-1并设置errno
。如果成功,则返回0且不设置errno
。手册页中刚刚提到了这与其他任何写入操作相同的行为,因为人们可能会惊讶地发现0长度写入可能会失败。
errno
如果write
针对文件,非阻塞套接字或阻塞套接字的调用返回0 的状态是什么?
在这种情况下,errno
未设置,因为write
没有失败。仅当输入缓冲区为零字节时才会发生这种情况。
什么时候以及如何
write
调用返回0而errno
不是0?
这不会发生。errno
设置要么返回值为-1,要么errno
未设置返回值为0或更大。
errno
ifwrite
通话返回正数的状态如何?会否定的?
该errno
值将不会被设置。它的值将与write
调用前相同。
还有其他系统调用可能会遇到相同的情况吗?
通常,系统调用将返回错误 或 成功。他们不会两者兼而有之。查看其他手册页的“返回值”部分,您将发现它们与大致相同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
}
回答:
从技术上讲,write
它既是系统调用又是C函数(至少在许多系统上)。但是,C函数只是一个调用系统调用的存根。Go不会调用此存根,而是直接调用系统调用,这意味着此处不涉及C(嗯,直到您进入内核为止)。
手册页显示了C存根的调用约定和行为write
。Go选择将其行为复制到自己的存根中syscall.Write
。实际的系统调用本身仅具有汇编语言界面。
以上是 C写调用和Go syscall.Write之间的区别 的全部内容, 来源链接: utcz.com/qa/411331.html