C写调用和Go syscall.Write之间的区别 [英] Differences between C write call and 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.
但是, 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:
- 如果
write
调用为文件,非阻塞套接字或阻塞套接字返回0,则errno
的状态是什么? - 何时以及如何
write
调用返回0并且errno
不为0? - 如果
write
调用返回正值,errno
的状态如何?会否定? - 是否还有其他系统调用可能遇到相同的情况?
- What is the status of
errno
ifwrite
call returning 0 for a file, a non-blocking socket, or a blocking socket? - When and how
write
call returning 0 anderrno
is not 0? - What is the status of
errno
ifwrite
call returning positive? Will it be negative? - 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,并设置了
errno
. - 如果成功,则结果为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 describeserrno
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
ifwrite
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 anderrno
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
ifwrite
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屋!