【问题标题】:What are these C directives doing and why was this library built this way?这些 C 指令在做什么,为什么这个库是这样构建的?
【发布时间】:2017-07-10 15:52:47
【问题描述】:

我正在浏览following library,但我无法理解几个函数的工作原理、它们在做什么以及为什么以这种方式构建库。该库提供加密工具。

例如,在包含测试的文件中,对象g1_t 以下列方式初始化:

g1_t a;
g1_new(a);
g1_null(a);

发现于:test_pc.c

g1_new()、g1_null() 等函数被定义为宏,例如:

#define g1_null(A)          CAT(G1_LOWER, null)(A)
#define g1_new(A)           CAT(G1_LOWER, new)(A)

发现于:relic_pc.h

CAT 又是一个宏定义为:

#define CAT(A, B)           _CAT(A, B)

随后,

#define _CAT(A, B)          A ## B

发现于:relic_util.h

此外,G1_LOWER 定义为:

#define G1_LOWER            ep_

发现于:relic_pc.h

我了解基本的预处理指令。例如,我知道## 正在连接两个标记。但是,我看不到这些指令如何能够创建/取消(以及许多其他事情)对象g1_t。这种设计格式对我来说很陌生。任何人都可以就这些指令的作用以及为什么以这种方式构建软件(即优势)提供一些见解吗?

【问题讨论】:

  • g1_new(a) 扩展为ep_new(a),其中ep_new 可能是一个函数或另一个宏。
  • 所以 ep_new(a) 和 ep_null(a) 被调用。但是你可以配置你的编译器将预处理器的输出输出到一个文件中,然后你就可以查看了。
  • 查看预处理器的输出。那是实际执行的代码,你可以从那里向后工作。
  • github 托管该库。研究git log 的输出可能会有所帮助。可能不。 (我假设您已经阅读了代码中的所有 cmets。)
  • 荒谬的编程风格。几乎无法调试的问题的根源。血腥的“预处理大师”,在编译时粘合函数名称。很难找到比这更愚蠢的了。

标签: c c-preprocessor software-design


【解决方案1】:

像往常一样,答案将是“历史原因”。通常,源代码曾经(并且可能仍然是)使用具有不同 C 方言和/或限制和/或兼容性要求的多个编译器为多个平台编译。

例如:

  • 与定义不同名称的函数的另一个库的兼容性
  • 与对标识符长度有严格限制的编译器/链接器平台兼容
  • 迁移/重构练习中的化石代码,其中所有函数都已重命名
  • 产品差异化练习,其中功能子集从具有不同函数名称的相同代码库编译(或此类练习的剩余部分)

C 语言已有 45 年历史:ISO C11 并不总是存在,许多正在使用、维护和定期编译的代码都可以追溯到 C11 之前的时代(或者实际上是 C89 之前的时代)。

在这种情况下我注意到 GitHub 历史中有一条评论说“将 ED 模块与 EC 模块集成”。可能这与那种类型的运动有关,例如允许在不同的编译单元中以不同的名称调用某些常用函数。

【讨论】:

    猜你喜欢
    • 2017-03-06
    • 2015-01-05
    • 2022-07-21
    • 2021-07-25
    • 2019-11-20
    • 1970-01-01
    • 1970-01-01
    • 2010-11-05
    • 2015-07-07
    相关资源
    最近更新 更多