【问题标题】:How's GNU extended function running when didn't defined _GNU_SOURCE未定义 _GNU_SOURCE 时 GNU 扩展功能如何运行
【发布时间】:2019-04-16 01:54:38
【问题描述】:

我在不同平台上测试了诸如“wcstoq”之类的GNU扩展功能。 一开始我没有用 D_GNU_SOURCE 编译测试用例,所以得到如下编译警告:

wcstoq.c:31:12: warning: implicit declaration of function 'wcstoq'; did you mean 'wcstol'? [-Wimplicit-function-declaration]
     retval=wcstoq(nptr,endptr,base);
            ^~~~~~
            wcstol

当我使用 gdb 调试这个测试用例时,它进入了与我定义 _GNU_SOURCE 的情况相同的正确函数。 但是当我没有定义 _GNU_SOURCE 时,函数就出错了。

例如:

当我在 x86_64 中测试超出范围的情况时,它应该设置retval= LLONG_MAX(0x7FFFFFFFFFFFFFFF),但它实际上设置了retval= -1(0xFFFFFFFFFFFFFFFF)。 当我在其他平台 ppc 中测试时,结果也让我感到困惑,它实际上设置了retval=0x000000007FFFFFFF。 当我定义_GNU_SOURCE时,函数在x86_64和ppc中运行正常,它都返回LLONG_MAX(0x7FFFFFFFFFFFFFFF)

我的问题是:

1 为什么我没有定义_GNU_SOURCE,但是gcc还是能找到正确的函数?

2 为什么gcc找对了,函数还是失败了,有些情况下函数还能用,有些时候就出错了?

3 为什么不同平台的功能失败结果不同,架构平台或其他因素如何影响不同的结果?

4 GNU 扩展函数的正确使用方法?

谢谢!

【问题讨论】:

  • 在您显示的情况下没有 prototype 定义,因此编译不知道参数的大小(或数量)。 external 符号存在,因为它不是宏或内联符号。
  • 我认为 4) 的最佳答案是您应该定义 _GNU_SOURCE 以使库标头包含 GNU 扩展的原型。完全没有声明,编译器假定返回类型是int
  • 谢谢,@PeterCordes,你知道更多关于隐式声明函数的行为的信息吗,不仅是返回类型,还有一些输入或输出参数,是不是意味着这个函数的行为是不可预测或未定义?尤其是对于 GNU 扩展函数?
  • 谢谢@ThomasDickey,但我很困惑和好奇为什么即使没有定义_GNU_SOURCE也可以调用该函数,以及为什么该函数的行为或输出在不同平台上不一样

标签: gcc compilation gnu cpu-architecture glibc


【解决方案1】:

隐式函数声明,默认启用的 GCC 扩展,使用返回类型 int,但函数定义为返回 long long。有了这样的类型不匹配,任何事情都可能发生。在实践中,结果取决于调用约定,这就是它们因架构而异的原因。

你真的应该用-Werror=implicit-function-declaration 编译(或使用C++)。近二十年前(在 ISO/IEC 9899:1999 中)从 C 语言中删除了隐式函数声明,但我们仍然无法更改 GCC 默认值,因为太多的 autoconf 检查会中断,导致软件意外丢失功能。

(我认为您的意思是在您的问题中写 retval 而不是 errno。)

【讨论】:

  • 也许值得一提的是,在 ISO C89 中允许隐式声明。但是,是的,在后来的 ISO C 标准(和 C++)中是不允许的,并且同意这通常是一个坏主意。即使没有-Wall,GCC 也会发出警告是有原因的。
猜你喜欢
  • 2011-10-23
  • 1970-01-01
  • 1970-01-01
  • 2017-10-21
  • 2012-03-12
  • 1970-01-01
  • 2018-02-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多