首页 文章

如何声明先前在包含库中声明的变量而不丢失其属性?

提问于
浏览
0

我对于声明属于库的变量的典型方法有疑问 . 例如,使用 getopt.h 库 . 它声明 opterroptarg ,以便它们可以在 getopt() 函数调用之外使用;我认为它们可能对这些变量有不同的声明,具体取决于编译器的实现 .

我尝试了一些可能的解决方案并在Windows gcc中编译它们(包括 <getop.h> 在内的所有解决方案):

  • 以与在/ usr / include / getopt.h中声明变量相同的方式声明变量 . 这编译时没有在Windows中抛出警告/错误,但我认为不能保证在其他编译器/操作系统中会发生同样的事情,并且很可能最终会在编译时抛出错误,所以我认为这种方式不是制作便携式C代码的正确方法 .

  • 只需以 extern int opterrextern char * optarg 这样的最简单方式声明变量 . 这给了我一个警告"Redeclared without the dll import atribute: previously dll import ignored"(getopt.h中的变量声明为 extern int __declspec(dllimport) opterrextern char __declspec(dllimport) *optarg ) .

  • 如果它们包含在库( Headers )中,我的变量代码中没有声明 - 只需使用 #include <getopt.h> 而不对变量进行其他声明 . (这似乎不是最简单的编码方式;我认为变量应该在所有使用它们的文件中声明 .

那么如何编写便携和干净的代码呢?

2 回答

  • 1

    头文件如 getopt.h 不是库 . 但是,它是构建库的人员使用的文件,用于声明作为库的一部分可用的变量和函数 . 它也可供库的用户使用,因此通过在代码中包含 Headers ,编译器将知道库是如何构建的 . 这是 Headers 的重点;他们确保可以使用函数和变量的一致声明来编译单独的源文件 .

    您的选项(1)不可移植;诸如 __declspec(dllimport) 之类的细节在Unix系统(或标准C)中没有任何意义 .

    您的选项(2)无法正常工作;合理地,编译器抱怨有相同变量的竞争声明 .

    你的选择(3)不起作用;没有先前的声明你不能使用变量 . 如果没有为optarg指定声明,则无法访问它 .

    明确的选项(3) - 使用 #include <getopt.h> - 正是最好的方法 .

    下面的答案的其余部分说了很多,但是写出来是因为选项(3)的原始版本没有像现在这样清晰 .

    因此,如果您的目的是编写可移植且干净的代码,则可以使用提供的标头使代码具有可移植性和清洁性 . 如果要处理特定于平台的问题(例如 __declspec(dllimport) ), Headers 会为您处理 . 您的代码是干净的,因为它只使用由编写库的人员编写的标头提供的声明 . 它对于创建它的平台是正确的 .

    基本上,如果在您感兴趣的所有平台的标头中定义了服务(函数和变量),则使用该标头,不要试图对系统进行二次猜测 . 如果由于声明在不同平台上的不同标头中或在某些平台上不可用而遇到问题,则必须更加努力,但目标应始终是尽可能使用系统提供的标头 . 您最终可能会在系统中使用封面 Headers (可能是 #include "wrapper/getopt.h" ),当它可用时只包含 <getopt.h> ,但在那些不可用的平台上提供等效声明 . 对于基本功能不可用的平台,您需要一个回退实现 . 或者,如果行为在不同的机器上完全不同,则将代码编写到您自己设计的抽象层中,然后在不同的机器上以不同的方式实现抽象 .

    请注意,C标准定义 <stdio.h> 中的内容 . 您可以放心使用C标准所说的内容 . 实施可以提供超出标准的扩展;您不能在可移植代码中使用这些扩展(尽管您可以在干净的代码中使用它们) . 你'd be foolish indeed to try second guessing or repeating what'在 <stdio.h> ;它是一个庞大而复杂的 Headers . 便携式代码当然不能尝试使用除了之外的任何东西本地 <stdio.h> 可靠 .

    最后,请记住,编译器正确地看到了一个转换单元(TU),它是C预处理器组合来自命名源文件的源代码及其包含的头文件的结果,通过条件包含和从头文件中排除材料来修改源代码 . 编译器不知道(诊断或调试代码除外)任何特定令牌的来源;它只是单个TU的一部分 .

  • 3

    getopt.h 不是库,而是头文件 . 该文件的大部分将是DLL中定义(实现)的函数的声明 . 该文件似乎也声明了一些变量 opterroptarg . 因此,您的第三个项目"not declare the variables"是正确的,除了通过包含带有 #include "getopt.h" 的头文件,您实际上是在声明变量 . 换句话说,头文件的整个要点是向包含它们的所有那些编译单元提供正确且一致的函数(和变量)声明 . 有关示例,请参阅Include directive中的目的部分 .

相关问题