15

我正在为大学做一个练习,我必须在退出时返回一个值,该值实际上是一个计数。这可能高于 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

4 回答 4

23

这个主题的真正问题是,在我的代码中调用这个宏与除以 256 是一样的吗?

它可能总是在子进程正常终止的情况下工作(即,通过调用exit(),而不是通过分段错误、断言失败等)。

存储的状态waitpid()编码子进程终止的原因和退出代码。原因存储在最低有效字节中(由 获得status & 0xff),退出代码存储在下一个字节中(由 屏蔽status & 0xff00和提取WEXITSTATUS())。当进程正常终止时,原因为0,因此WEXITSTATUS仅相当于移位8(或除以256)。但是,如果进程被信号(如 SIGSEGV)杀死,则没有退出代码,您必须使用WTERMSIG从原因字节中提取信号号。

于 2009-04-30T20:50:58.570 回答
3

如果状态变量是一个有符号的 16 位整数(一个 'short')在机器上 'int' 是一个 32 位数量,并且如果退出状态在 128..255 范围内,那么 WEXITSTATUS() 仍然给你一个正确的值,除以 256 或简单地向右移动会给你一个不正确的值。

这是因为 short 将被符号扩展为 32 位,并且屏蔽会撤消符号扩展,从而在结果中留下正确的(正)值。

如果机器使用 16 位整数,那么 WEXITSTATUS() 中的代码可能会先移位然后掩码以确保类似的行为:

#define WEXITSTATUS(status) (((status)>>8) & 0xFF)

正是因为实现为您处理了这些细节,您应该使用 WEXITSTATUS() 宏。

于 2009-05-01T01:06:33.290 回答
3

据我通过检查 Single Unix Spec 得知,您的系统恰好将退出状态存储在倒数第二个八位字节中,但我不相信标准会这样做。因此,您应该至少出于以下几个原因使用宏:

  • 他们是正确的。位移负数在不同的平台上做不同的事情。它是否按照您想要的方式工作?我不知道。
  • 它们很简单。它立即清楚做什么WEXITSTATUS。其他方法则更少。如果你看到手卷版的WIFSIGNALED,你会认出来吗?需要多长时间WIFSIGNALED
  • 它们是便携式的。既然规范是这样说的,它就可以在每个系统上工作(至少几乎每个类 Unix 系统)。
于 2012-02-03T22:45:25.757 回答
2

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

您应该只WEXITSTATUS在已知正常退出的进程上使用。该信息由WIFEXITED宏给出。

这个主题的真正问题是,在我的代码中调用这个宏与除以 256 是一样的吗?

该宏使代码更具可读性,并且保证可以在任何符合 Posix 的实现上工作。据我所知,Posix 没有指定状态的格式,所以你不能指望你的代码在任何地方都能工作。

于 2009-04-30T19:29:36.907 回答