【问题标题】:Prevent inclusion of stdio.h (or other standard header)防止包含 stdio.h(或其他标准头文件)
【发布时间】:2016-04-04 00:17:05
【问题描述】:

我使用的一个代码库在历史上曾尝试过——有目的地——避免对 stdio.h 的依赖。它有自己的打印格式和机制,这些是应该用来代替 printf 等的。

但是有人经常添加一个必须引起注意和删除的依赖项。所以我试着为最简单的情况发出警报:

#if !defined(NDEBUG)
   void printf(float dont_link_with_stdio_h);
#endif

gcc 的人们似乎也在考虑停止简单的错误,因为如果你这样做会有一个有用的信息......无论你是否包含 <stdio.h>

内置函数“printf”的类型冲突

有一种方法可以关闭此警告 (-fno-builtin)。并且有各种各样的方法可以做一些事情,比如过滤符号转储中你不想在那里的东西......

但是有没有一种非常简单且不会引起警告(如果您没有包含 stdio.h)的方法来提醒某人他们引入了不需要的 printf 用法?

【问题讨论】:

  • 你能不删除库的编译版本(.lib),这样它就不会编译/链接吗?
  • @LeeTaylor 我宁愿不要篡改编译环境,该环境用于包含此库的其他内容(如果他们愿意,这些内容可以免费包含 stdio.h)。我正在寻找比使用我尝试的方法并添加 -fno-builtin...e.g. 更少干扰的东西。可以单独在源内部完成的事情。
  • 重新定义类型/结构而不是函数。
  • 你能#define printf dont_include_stdio_h(或#define printf _Static_assert(0, "Do not include stdio.h"))吗?
  • @Cornstalks 我没有想到#define,因为我担心它不会给出明显的信息......但是通过将它变成垃圾作为 `#define printf $dont_include_stdio_h$ 它正确以一种足够好的警报的方式把事情搞砸了。我会把它作为答案......

标签: c stdio


【解决方案1】:

您可以将printf 重新定义为一些会导致编译或链接错误的讨厌值。例如:

#define printf do_not_include_stdio_h
#include <stdio.h>

int main(void) {
    printf("Hello, world!\n");
    return 0;
}

produces the output:

undefined reference to `do_not_include_stdio_h'

如果您希望宏名称更加晦涩,您可以使用该宏,或者如果您担心某个可怜的人会定义 do_not_include_stdio_h,请包含无效符号。

您可以在编译器标志中设置宏定义,这样您就不必手动编辑文件。例如:

gcc -Dprintf=do_not_include_stdio_h my_file.c

【讨论】:

    【解决方案2】:

    我根本不会接触源文件。我会修改构建脚本。更容易维护,也更容易防止人们绕过限制(例如,通过更改导致编译失败的代码)。

    例如,在 makefile 中,假设您有一个构建所有内容的 all 目标

    all:
    
       grep stdio *.h *.c
       if ["$?" -eq 0 ]; then
           echo "Do not use stdio.  Contact Joe for info"; exit 2;
       fi
    
       <other stuff to do the build here>
    

    您也可以对特定目标执行此操作。例如,如果您有一个编译 .c 文件以生成 .o 文件的目标,则只需在编译之前检查 .c 文件即可。

      %.o : %.c
    
           grep stdio $<
           if ["$?" -eq 0 ]; then
               echo "Do not use stdio.  Contact Joe for info"; exit 2;
           fi
    
           $(CC) -c $(CFLAGS) $(CPPFLAGS) $< -o $@
    

    您现在唯一的问题是,如果有人决心绕过您的限制,该怎么办(例如,#include "bypass.joe",其中bypass.joe 有一个#include &lt;stdio.h&gt;)。为此,查找生成依赖项的工具(例如gcc -MMmakedepend 等)并使用它来设置一种方法来搜索您的源文件所依赖的所有文件。如果有人这么确定,还要对你的 makefile 设置保护,这样只有你可以编辑它们。

    编辑:如果您设置了生成依赖文件的工具,只需在该文件中搜索stdio。如果任何编译单元直接或间接包含 stdio.h ,那么它将被列在依赖文件中。

    【讨论】:

    • 像这样 grepping 的问题(除了侵入我宁愿避免的 makefile,因为它们是由另一个进程生成的)是你担心如果它在评论中会怎样,如果它是#ifdef'd 并且不适用,等等。有一些第三方文件是.c,它们有自己的调试模式标志分开,所以必须有例外列表等......
    • 如果可以选择“侵入”makefile 和“侵入”项目中的所有编译单元(也称为源文件),我会选择第一个。即使在一个复杂的项目中,makefile 的数量也很少超过编译单元的数量。有一些技术可以确保在自动生成的 makefile 中进行自定义处理,递归使用 make 等。
    • 合理,感谢您的选择,赞成。但对于我的特殊情况,更好的平衡选择是不接触 makefile...
    【解决方案3】:

    为了防止包含&lt;stdio.h&gt;,我会选择

    #if !defined(NDEBUG)
    #if defined(EOF)
    #error Do not include stdio.h, contact Joe for more information
    #endif
    #endif
    

    【讨论】:

    • 很好......虽然这样做的问题是,如果这个包含是 stdio.h 之后,它只会停止包含。如果之前也包含此标头,我想抢占它...
    猜你喜欢
    • 2018-06-15
    • 1970-01-01
    • 1970-01-01
    • 2013-11-21
    • 1970-01-01
    • 2013-09-20
    • 2019-06-28
    • 1970-01-01
    • 2021-12-15
    相关资源
    最近更新 更多