【问题标题】:What does (*(int *)&(w)) mean in c programming?(*(int *)&(w)) 在 c 编程中是什么意思?
【发布时间】:2020-02-19 12:59:00
【问题描述】:

我正在学习过程,在下面的代码sn-p中:

/* 
 * fork10 - Synchronizing with multiple children (wait)
 * Reaps children in arbitrary order
 * WIFEXITED and WEXITSTATUS to get info about terminated children
 */
void fork10()
{
    pid_t pid[N];
    int i, child_status;

    for (i = 0; i < N; i++)
    if ((pid[i] = fork()) == 0) {
        exit(100+i); /* Child */
    }
    for (i = 0; i < N; i++) { /* Parent */
        pid_t wpid = wait(&child_status);
        if (WIFEXITED(child_status))
            printf("Child %d terminated with exit status %d\n", wpid, WEXITSTATUS(child_status));
        else
            printf("Child %d terminate abnormally\n", wpid);
    }
}

当我跟踪 WIFEXITED 函数定义时,这就是我得到的:

#define WIFEXITED(x)    (_WSTATUS(x) == 0)
#define _WSTATUS(x) (_W_INT(x) & 0177)
#define _W_INT(w)   (*(int *)&(w))  /* convert union wait to int */

我有两个问题:

  1. 为什么要用掩码0177而不是0b1111111,我见过很多次了,用八进制数比其他格式有什么好处?我个人觉得二进制更直观。
  2. (*(int *)&amp;(w))是什么意思?

谢谢!

【问题讨论】:

  • 恕我直言 0177 是写 0x7F 的一种混淆方式。
  • 是的,八进制只是纯粹的混淆。 127 可读性更强,0x7F 可读性最高。
  • 0b1111111 不清楚。是6个吗? 7?要知道0b1111111 的含义,必须花时间数一数。 (我发现0x7F 在这里最清楚:除了最重要的位之外的所有)

标签: c process operating-system


【解决方案1】:

诸如0b1111111 之类的二进制常量不是由 C 标准定义的,并且在某些 C 实现中作为扩展引入了一些较晚的时间,因此早期的代码必须使用八进制和十六进制常量,并且程序员已经习惯了它们。此外,八进制更紧凑,与0b1111111 相比,我可以更轻松地计算0177 中设置的位数。人们很快就会习惯于知道7 意味着设置了三位。

在(*(int *)&amp;(w))中,&amp;(w)取w指定的对象的地址。然后(int *) 将该地址从“指向 w 类型的指针”类型转换为“指向 int 的指针”。然后* 取消引用该指针,名义上产生int 值。

目的是访问w 的第一个字节,就好像它们是int,有效地获取w 中的原始位,而不是将其解释为结构或任何其他类型。这称为别名。

C 标准不支持这种方式的别名,但许多 C 实现允许这样做,并且您显示的代码似乎是专门为这种实现编写的。

获取对象原始位的一种受支持的方法是单独复制字节,如下所示:

int b;
memcpy(&b, &w, sizeof b);

虽然这看起来像一个函数调用,但好的编译器会将其识别为访问w 的第一个字节的请求,就好像它们是int 一样并对其进行优化。结果可能是单个加载指令。但是,将其包装到一个产生int 作为值的宏中会涉及一些复杂性,我将在其他地方进一步讨论。 (如果需要,您可以就此提出新问题。)

【讨论】:

  • “C 标准不支持这种方式的别名” 假设w 是注释所指示的联合。 C17 6.7.2.1/16 “指向联合对象的指针,经过适当转换,指向其每个成员,反之亦然。”此外,有效类型的规则也有一个例外,C17 6.5/7:“一个对象的存储值只能由具有以下类型之一的左值表达式访问: - 与有效类型兼容的类型object ... - 一种聚合或联合类型,在其成员中包含上述类型之一”。
  • 请注意,即使标准不允许,对于特定于编译器的库(例如此处检查的库)依赖于特定于该编译器的扩展也是合法的。
【解决方案2】:

1 为什么使用掩码 0177 而不是 0b1111111 ...?

(此答案仅解决您问题的这一部分)

因为0b1111111 不是每个6.4.4.1 Integer constants 的C 整数常量:

语法

1

      integer-constant:
            decimal-constant integer-suffixopt
            octal-constant integer-suffixopt
            hexadecimal-constant integer-suffixopt
      decimal-constant:
            nonzero-digit
            decimal-constant digit
      octal-constant:
            0
            octal-constant octal-digit
      hexadecimal-constant:
            hexadecimal-prefix hexadecimal-digit
            hexadecimal-constant hexadecimal-digit
      hexadecimal-prefix: one of
            0x   0X
      nonzero-digit: one of
            1   2   3   4   5   6   7   8   9
      octal-digit: one of
            0   1   2   3   4   5   6   7
      hexadecimal-digit: one of
            0   1   2   3   4   5   6   7   8   9
            a   b   c   d   e   f
            A   B   C   D   E   F
      integer-suffix:
            unsigned-suffix long-suffixopt
            unsigned-suffix long-long-suffix
            long-suffix unsigned-suffixopt
            long-long-suffix unsigned-suffixopt
      unsigned-suffix: one of
            u   U
      long-suffix: one of
            l   L
      long-long-suffix: one of
            ll   LL

说明

2 整数常量以数字开头,但没有句点或 指数部分。它可能有一个指定其基数的前缀和一个 指定其类型的后缀。

3 十进制常量以非零数字开头,由 十进制数字序列。八进制常数由前缀 0 组成 可选地后跟仅由 0 到 7 的数字序列。一个 十六进制常量由前缀 0x 或 0X 后跟 十进制数字和字母 a(或 A)到 f(或 F) 值分别为 10 到 15。

按照标准,C 仅支持十进制、八进制和十六进制整数常量。

【讨论】:

    【解决方案3】:
      1. 它的优点是不需要任何额外的符号作为数字(十六进制系统是以 16 为基数,因此需要 0-9 之外的六个额外符号)。它也用于数字显示器。
    1. 您正在尝试将其转换为整数指针并从中引用值。

    【讨论】:

      【解决方案4】:

      关于您的第一个问题:二进制文字不是 C 标准的正式组成部分(自 C++14 以来只是 C++ 的一部分),因此使用八进制文字而不是使用它们可以提高可移植性。

      关于您的第二个问题:&amp;w 获取w 的地址,然后将其转换为指向取消引用的 int ((int*)&amp;w) 的指针。这实际上是从w 读取内存,就好像w 是int。

      【讨论】:

        【解决方案5】:

        您应该检查此链接,它将帮助您使用(顺时针/螺旋规则)解决任何问题

        http://c-faq.com/decl/spiral.anderson.html?fbclid=IwAR3V_KR4VwO33UvbO4LgN3AIW_79QBWAR9qHO2KHyyJgEuIKiFQOQTCec5U

        ((int)&(w)) 首先 &w 表示 w 的地址,其中 & 是地址运算符然后 (int *) 意味着创建指向整数的指针,所以(直到这一步你有指向 w 地址的指针)最后 * 在这个指针之前意味着(你访问了 w 的值)

        【讨论】:

          猜你喜欢
          • 2016-07-28
          • 2015-10-18
          • 1970-01-01
          • 2010-11-19
          • 1970-01-01
          • 1970-01-01
          • 2015-01-05
          • 1970-01-01
          相关资源
          最近更新 更多