在退出时使用C语言中的WEXITSTATUS宏,与通过将退出状态除以256有何益处?

16

我正在为大学做一项练习,其中我必须使用exit返回一个值,这个值实际上是某个东西的计数。这个值可能超过255(exit()无法处理),但老师建议使用测试数据,其中计数永远不会超过该值。

在所有这些之后,我需要处理这个计数值,也就是退出状态码,我通过使用waitpid()在主进程中获取了这个值。令我惊讶的是,如果子进程返回1,则在主进程中的“真实”值为256,2为512,依此类推......

我需要打印这个值,所以我只需将它除以256即可完成。然而,如果我使用WEXITSTATUS()宏,我也可以得到我想要的值......

我查看了C源代码,发现如下内容:

#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)

我了解这里发生的情况,例如,512在二进制中为10 0000 0000,向右移8位将给出00 0000 0010,这是十进制中的2。但是,在这个宏中,我不理解&运算符以及0xff00似乎是一个随机数(可能并不是,但它来自哪里?)。这到底是做什么的,为什么宏中有“& 0xff00”?没有它行不行?

而这个话题的真正问题是,在我的代码中调用这个宏是否与除以256相同?

4个回答

23

那么这个话题的真正问题是,调用我的代码中的这个宏和除以256是否相同?

这通常适用于子进程正常终止(即通过调用exit()而非分段错误、断言失败等方式)的情况。

waitpid() 存储的状态编码了子进程终止的原因和退出码。原因存储在最低有效字节中(通过 status & 0xff 得到),退出码存储在其后的一个字节中(通过掩码 status & 0xff00 和提取函数 WEXITSTATUS() 得到)。当进程正常终止时,原因为0,所以 WEXITSTATUS 相当于向左移动8位(或除以256)。然而,如果进程被信号(例如 SIGSEGV)杀死,则没有退出码,你必须使用 WTERMSIG 来从原因字节中提取信号编号。


3
如果状态变量是一个有符号的16位整数(即“short”),在一个“int”是32位的机器上,如果退出状态在128..255范围内,则WEXITSTATUS()仍然会给出一个正确的值,除以256或者简单地向右移动将会得到一个不正确的值。
这是因为短整型会被符号扩展到32位,并且屏蔽操作会撤销符号扩展,从而在结果中留下正确(正)的值。
如果机器使用16位整数,则WEXITSTATUS()中的代码可能会执行移位然后屏蔽操作,以确保类似的行为:
#define WEXITSTATUS(status) (((status)>>8) & 0xFF)

因为实现会为您处理此类细节,所以您应该使用WEXITSTATUS()宏。

3
据我从查阅 Single Unix 规范得知,您的系统似乎将退出状态存储在倒数第二个八位组中,但我不认为标准是这样的。因此,您应该使用宏至少有以下几个原因:
  • 它们是正确的。在不同的平台上,对负数进行位移会产生不同的效果。在您的系统上是否按您所需的方式工作?我不知道。
  • 它们很简单。使用 WEXITSTATUS 时立即就能明确其作用。其他方法则不太一样。如果您看到手写版本的 WIFSIGNALED,您能识别出来吗?与 WIFSIGNALED 相比需要多长时间?
  • 它们是可移植的。由于它是规范指定的方法,因此它将在每个系统上(至少几乎所有类 Unix 系统)都能正常工作。

2

在这里,0xff00是一个二进制掩码 (链接文本)。将它与一个值进行AND操作会将除了第二个字节(从右边数)的所有位都设置为零。

您应该仅对已知正常退出的进程使用WEXITSTATUS。这些信息由WIFEXITED宏提供。

而在这个主题中真正的问题是,调用这个宏和除以256是一样的吗?

这个宏使代码更易读,并且保证在任何符合Posix标准的实现上工作。据我所知,Posix没有指定状态的格式,因此您不能期望您的代码在任何地方都能工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接