声明一个与标准函数同名的全局变量会在clang(但不是gcc)中产生错误。这不是由于头文件中的先前声明。我可以通过编译以下单行文件来获取错误:
extern void *memcpy[];
Clang说
foo.c:1:14: error: redefinition of 'memcpy' as different kind of symbol
foo.c:1:14: note: previous definition is here
显然,这只发生在一些标准功能上。 printf
产生错误,fprintf
会产生警告,fseek
只会有效。
为什么这是一个错误?有办法解决它吗?
动机。我使用C编译器作为编译器后端。 C代码以编程方式生成。生成的代码依赖于字节级地址算法和指针类型转换。所有外部符号都声明为extern void *variablename[];
。
答案 0 :(得分:2)
根据C标准(ISO 9899:1999第7.1.3节),“库定义的所有外部标识符都保留在托管环境中。这实际上意味着用户提供的外部名称不能与库匹配名字“。
您可以通过为所有标识符添加唯一的前缀来轻松解决问题,例如: “mylang_
”。
作为替代方法,您可以通过使用LLVM或GCC -ffreestanding
标志来避免此问题,该标志将为非托管环境编译代码。 (C标准规定限制仅适用于托管环境。)在这种情况下,您可以使用所需的所有名称(除了main
,这仍然是您的程序的入口点),但您必须使自己安排图书馆。这就是操作系统内核可以合法地定义自己的C库函数版本的方法。
答案 1 :(得分:1)
这里解释了其原因,下面给出了相关的摘录。 http://www.gnu.org/software/libc/manual/html_node/Reserved-Names.html 我在gcc中也遇到错误。
来自ISO C标准的所有库类型,宏,变量和函数的名称都是无条件保留的;您的程序可能不会重新定义这些名称。如果您的程序明确包含定义或声明它们的头文件,则保留所有其他库名。这些限制有几个原因:
- 如果您使用名为exit的函数执行与标准退出函数完全不同的操作,那么阅读代码的其他人可能会非常困惑。防止这种情况有助于使您的程序更易于理解,并有助于模块化和可维护性。
- 它避免了用户意外重新定义其他库函数调用的库函数的可能性。如果允许重新定义,那些其他功能将无法正常工作。
- 它允许编译器在调用这些函数时进行任何特殊的优化,而不会被用户重新定义。一些库设施,例如用于处理可变参数(参见Variadic函数)和非本地出口(参见非本地退出)的设施,实际上需要C编译器方面的大量合作,并且相对于在实现中,编译器可能更容易将它们视为语言的内置部分。
醇>
该页面还描述了其他受限制的名称。