【问题标题】:Preprocessor macros I don't understand我不明白的预处理器宏
【发布时间】:2011-02-18 16:46:21
【问题描述】:

我目前正在查看我在网上找到的一些源代码,这些源代码以我不理解的方式使用了预处理器宏。它实现了四边数据结构。 希望有人可以为我澄清事情!

typedef int edge_ref;

typedef struct {
    edge_ref next[4];
    void *data[4];
    unsigned mark;
} edge_struct;

#define ROT(e) (((e)&0xfffffffcu)+(((e)+1)&3u))
#define SYM(e) (((e)&0xfffffffcu)+(((e)+2)&3u))
#define TOR(e) (((e)&0xfffffffcu)+(((e)+3)&3u))

#define ONEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[(e)&3]
#define ROTRNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+1)&3]
#define SYMDNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+2)&3]
#define TORLNEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[((e)+3)&3]

#define MARK(e)  ((edge_struct *)((e)&0xfffffffcu))->mark

这就是它们的使用方式:

edge_ref e;
e = (edge_ref) malloc(sizeof(edge_struct));
ONEXT(e) = e;
SYMDNEXT(e) = SYM(e);
ROTRNEXT(e) = TOR(e);
TORLNEXT(e) = ROT(e);
MARK(e) = 0;
return e;

这只是概述我遇到的问题的摘录。整件事情都可以找到here

【问题讨论】:

  • 我的眼睛,流血了。猜猜有人没有告诉开发人员函数和宏之间的区别。去打谁写的,它会让你感觉更好。
  • 我认为这是一个非常速度优化的实现
  • 是否有一些您不理解的特定内容(例如 edge_struct 指针的位掩码)或者整个事情难以理解?你的问题有点开放式。
  • (((e)&0xfffffffcu)+(((e)+1)&3u)) 我根本不明白.. 什么是 0xfffffffcu 例如

标签: c data-structures macros c-preprocessor binary-operators


【解决方案1】:

这些宏只是一个简单的代码替换。至于在做什么是另一回事。

ONEXT(e) = e;

变成 ((edge_struct *)((e)&0xfffffffcu))->下一个[(e)&3] = e;

在我看来,他们正在加载一个包含与地址相关的数据的结构。

不要对宏感到不知所措。只需将代码替换为宏并弄清楚它的作用。之后重新编写并添加一些 cmets,这样下一个人就不必经历你现在的情况。

【讨论】:

    【解决方案2】:

    0xfffffffcu 只是一个无符号常量,所有位都设置为 1,除了最后 2 位为 0,即11111111111111111111111111111100。它被用作操纵e 的底部两位的掩码。这些宏的重点似乎是让您可以处理一个由 4 个结构组成的数组,您将其视为一个循环数组(即模 4 索引)。

    【讨论】:

    • 现在对我来说很有意义,因为数据结构称为 quad edge
    【解决方案3】:

    等一下……

    typedef int edge_ref;
    
    #define ONEXT(e) ((edge_struct *)((e)&0xfffffffcu))->next[(e)&3]
    
    e = (edge_ref) malloc(sizeof(edge_struct));
    ONEXT(e) = e;
    

    malloc 的返回值被强制转换为有符号整数,使用时不检查 NULL,并用无符号整数屏蔽...

    我不知道这段代码的用途,但我强烈建议不要将其用于任何目的

    【讨论】:

      【解决方案4】:

      他们假设 malloc 函数返回的内存地址至少对齐四个字节。由于他们假设所有内存分配都会产生一个低两位设置为零的值,因此他们使用这两位来存储信息。因此,要获取结构中的数据,他们需要清除这两个位以获取真实地址:

      ((edge_struct *)((e)&0xfffffffcu))
      

      因此,edge_ref 是一个指向 edge_struct 类型对象的指针,也是该对象内部数组((e)&3u 位)的索引。

      文件位于:聪明,但 euurrgghh(与 XOR list 一起)。

      【讨论】:

      • 在 64 位操作系统上运行时,这种方法不会也导致问题吗?
      • @guest:是的,它会严重损坏,因为您会丢失地址的高 32 位。您可以将 0xffffffc 扩展到 64 位版本。
      • 感谢所有输入!还没有完全理解它,但是很好地掌握了正在发生的事情。
      【解决方案5】:

      我的猜测是他们已经为指针添加了标签,假设它们是对齐的。 (这就是为什么在取消引用之前有屏蔽操作)。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-15
        • 2015-07-31
        • 1970-01-01
        • 2010-09-19
        • 2020-02-09
        • 1970-01-01
        • 2011-01-26
        相关资源
        最近更新 更多