[英]Why doesn't gcc call abs function?
我有一些 C 代码
#include<stdio.h>
#include<stdint.h>
int32_t abs(int32_t x) {
int32_t mask = (x >> 31);
printf("mask is %d\n",mask);
return (x + mask) ^ mask;
}
int main(int argc, char *argv[])
{
int32_t i=-5;
printf("%d\n",abs(i));
return 0;
}
我用 GCC 编译它。
gcc -O0 -S -masm=intel
asm 代码在https://pastebin.com/4TGpSsdd
为什么gcc 不调用abs 函数而clang 调用。
该程序不调用 abs 函数和
执行代码「printf("mask is %d\\n",mask);」
我的 gcc 版本:
gcc (Ubuntu 4.8.4-2ubuntu1~14.04.3) 4.8.4
这是一个gcc错误吗?
abs
是一种内置在GCC,但锵取代建宏通过调用各自的库函数。
要解决此问题,您可以重命名您的函数(建议这样做;推理见下文)您可以使用-fno-builtin-abs
编译您的代码,或者您可以将您的函数标记为static
。
这是链接页面的引用:
is specified for an individual function).在ISO C90功能
abort
,abs
,acos
,[...]和vsprintf
被除非所有公认的内建函数-fno-builtin
指定(或-fno-builtin-
为单个功能被指定)。 所有这些函数都有以__builtin_
为前缀的相应版本。
C 标准指出,使用外部重新定义库函数是未定义的行为(C11 §7.1.3 1):
以下任何子条款(包括未来的库方向)和
errno
中的所有具有外部链接的标识符始终保留用作具有外部链接的标识符。
如果您将abs
定义为static
,则不会删除该调用。
stdlib.h
有一个函数int abs(int x)
。
您需要重命名您的函数。
abs
)对于 gcc 编译器来说是众所周知的。 它们被称为内置函数。 所以编译器知道这个函数做什么,而且在很多情况下它不必调用它。如果您重命名它 - 它将使用 -O0 https://godbolt.org/z/dLg26U生成呼叫
如果你想在启用优化的情况下调用它,你需要告诉编译器不要内联它。 https://godbolt.org/z/aHaEik
int32_t __attribute__((noinline)) myabs(int32_t x) {
这是一个gcc错误吗?
不。
abs
是 C 标准中定义的函数,它的原型由#include <stdlib.h>
提供为int abs (int)
。
然而,即使不包含该头文件,gcc 也有关于abs
内置知识,并且知道它应该做什么。 这适用于大多数用户正在使用的托管 C。
然而,在非托管 C 中,编译器不能对标准头文件中声明的函数的语义做出任何假设。 在 gcc 中,您会得到不受限制的响应。 独立式-freestanding
。
此外,即使没有开启优化( -O0
),gcc 也会折叠常量。 这是因为在
int x = 1 + 2;
您不能在运行时为静态存储中的x
进行初始化 - 与 C++ 相反,C++ 原则上可以在运行时对其进行初始化。 在你的情况下
abs (-5)
被折叠到5
。
由于您很可能不想使用-ffreestanding
,您可以使用-fno-builtin-abs
来-ffreestanding
有关abs
内置知识,这对于许多其他功能也是如此。 即使使用-fno-builtin-abs
选项,如果您更喜欢绝对值计算的优化版本并且没有对libc.a
/ libc.so
libcall,您也可以在代码中使用__builtin_abs
。
由于评论而独立的附录广告:C99 §4 一致性,说:
- 两种形式的一致性实现是托管和独立的。 符合要求的托管实施应接受任何严格符合要求的程序。 符合标准的独立实现应接受任何不使用复杂类型的严格符合程序,并且其中库条款(第 7 条)中指定的功能的使用仅限于标准头文件
<float.h>
、<iso646.h>
、<limits.h>
、<stdarg.h>
、<stdbool.h>
、<stddef.h>
和<stdint.h>
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.