【问题标题】:What is the logic behind defining macros inside a struct?在结构中定义宏的逻辑是什么?
【发布时间】:2010-06-16 08:58:04
【问题描述】:

正如标题所示,我质疑在结构中定义宏的原因。我经常在网络编程中看到这种方法,例如在 sn-p 之后:

struct sniff_tcp {
    u_short th_sport;               /* source port */
    u_short th_dport;               /* destination port */
    tcp_seq th_seq;                 /* sequence number */
    tcp_seq th_ack;                 /* acknowledgement number */
    u_char  th_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
    u_char  th_flags;
    #define TH_FIN  0x01
    #define TH_SYN  0x02
    #define TH_RST  0x04
    #define TH_PUSH 0x08
    #define TH_ACK  0x10
    #define TH_URG  0x20
    #define TH_ECE  0x40
    #define TH_CWR  0x80
    #define TH_FLAGS        (TH_FIN|TH_SYN|TH_RST|TH_ACK|TH_URG|TH_ECE|TH_CWR)
    u_short th_win;                 /* window */
    u_short th_sum;                 /* checksum */
    u_short th_urp;                 /* urgent pointer */
};

此示例来自 tcpdump 网站中的 sniffex.c 代码。

这是为了提高可读性和使代码更清晰吗?

【问题讨论】:

  • 也许原作者喜欢放假后回来,不必查看不同的文件来回忆那些宏的含义。
  • 如果是这种情况作者应该投资支持ctags的编辑器。
  • gcc 还有一个很棒的宏扩展功能。 (带 -E 选项)
  • @vpit3833:将宏放入结构或另一个文件中并不是唯一可能的选择。正常的方法是将宏放在同一个文件中,可能直接放在结构上方。
  • 个人喜好。有些人喜欢在结构之前或之后定义的宏,有些人喜欢在内部定义的宏。我更喜欢内部,尤其是当一个结构可能有多个具有不同值集的字段时。不过,我同意其他人的观点,枚举适用于采用有限数量值之一的字段。

标签: c macros struct


【解决方案1】:

嗯,定义的常量与其中一个字段的可能值相关。

因此,作者决定改进代码局部性,让 API 用户避免循环运行。似乎合乎逻辑。

否则,预处理器完全独立于代码。您甚至可以在表达式中添加定义。

【讨论】:

  • 好的,所以它没有任何其他功能。但这对我来说真的很奇怪,因为对我来说这只是让事情复杂化。我认为将无法在相应结构中调用的结构放入结构中没有意义。对我来说,如果你想要代码局部性,你可以把它放在结构之上。
【解决方案2】:

我们不得不怀疑它试图向我们传达宏只能与此结构中的数据一起使用,但这是一种糟糕且复杂的表示方式。

在 C++ 中,最好使用嵌套枚举和内联函数来完成此操作,但由于代码是 C,因此宏可能是最好的选择。

在我看来,它会降低可读性,我更希望看到结构之外的宏,并用 cmets 指示它们应该在哪里以及如何使用。这样一来,就无需猜测宏的确切用途,并且结构定义不会乱七八糟。

【讨论】:

    【解决方案3】:

    一个典型的用法如下所示

    包括

    假设您的第一个版本的 foo 有点如下所示。

    struct foo1 {
     int x;`enter code here`
     ...
    };
    

    明天你尝试通过以下方式增强结构 foo

    struct foo2 {
     union {
       int x;
       int y;
     } u;
    #define x u.x
    #define y u.y
    };
    

    上面所做的声明不会在你有的地方破坏编译 使用 foo_var.x 因为结构 foo_var.x 的新定义仍然有效并且是 只有 foo_var.u.x

    例如用法:

    struct foo {
     union {
       int x;
       int y;
     } u;
    #define x u.x
    #define y u.y
    };
    
    int main()
    {
      struct foo f;
    
      f.x = 1;
      f.y = 2;
    }
    

    【讨论】:

    • 这与帖子中的情况有些不同。但这是一个有趣的用法,谢谢。
    【解决方案4】:

    我认为,这不是“最佳实践”,应该将定义(用于值)保留在结构附近,而不是在结构内部。

    (更好的做法是枚举和 typedef 常量,这样如果没有正确输入,编译器会发出警告)。

    TH_OFF() 宏是另一种情况,它“隐藏”了另一个元素,所以也许可以将它放在这个位置(带有适当的注释)

    【讨论】:

    • +1 表示枚举。我喜欢对某些字段(例如状态)使用枚举,但我认为它不适合字段中的屏蔽位。
    • enum 是个坏主意...假设 16 位整数,您如何编写值为 0x8000 的枚举常量?这不可能。同样,在整数算术中使用有符号变量也是一个坏主意。
    【解决方案5】:

    作者的意图似乎是应该将属于一起的事物放在一起。因此,标志宏应该就在标志下方。同样的逻辑,宏定义与结构声明无关,因此宏属于那里。将它们放在结构的上方或下方没有任何问题。

    我想知道如果标志是一个带有 32 个标志宏和一些额外的默认组合宏的 u_long,作者是否会保持一致并做同样的事情?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-09-06
      • 2018-09-12
      • 2017-05-23
      • 2010-10-02
      • 1970-01-01
      • 2023-01-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多