- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
从理论上讲,inline
函数在 C 语言中具有内部/静态链接,也就是说,它们仅在单个翻译单元内可见。因此,在两个单独的文件中定义的内联函数应该无法相互看到,并且两者都有自己的地址空间。
我正在尝试使用以下文件
***cat a.c***
#include <stdio.h>
inline int foo()
{
return 3;
}
void g()
{
printf("foo called from g: return value = %d, address = %#p\n", foo(), &foo);
}
***cat b.c***
#include <stdio.h>
inline int foo()
{
return 4;
}
void g();
int main()
{
printf("foo called from main: return value = %d, address = %#p\n", foo(), &foo);
g();
return 0;
}
gcc -c a.c
gcc -c b.c
gcc -o a.out a.o b.o
b.o: In function `foo':
b.c:(.text+0x0): multiple definition of `foo'
a.o:a.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
上面的编译错误反射(reflect)了 b.c 可以看到 a.c 中的 foo
的定义并且编译失败(这不应该是内部链接内联函数的情况)。
如果我遗漏了什么,请帮助我理解。
编辑 1:正在尝试这个链接的理论。 https://www.ibm.com/support/knowledgecenter/en/ssw_ibm_i_71/rzarg/inline_linkage.htm
最佳答案
TL;DR: GCC 仍然默认使用其旧的 inline
语义,其中 inline
函数仍被编译为外部可见的实体。指定 -std=c99
或 -std=c11
将导致 GCC 实现标准语义;但是,IBM 编译器也不符合标准。所以链接仍然会失败,但会出现不同的错误。
从 C99 开始,没有声明链接的函数声明不会生成函数对象。内联定义只会与内联替换一起使用,编译器没有义务执行此优化。预计函数的外部定义存在于其他一些翻译单元中,并且如果使用函数对象,则必须存在这样的定义,无论是通过获取其地址还是在编译器选择不执行的上下文中调用内联替换。
如果内联函数是用 static
或 extern
声明的,那么函数对象会被编译,并带有指示的链接,从而满足函数对象是定义。
在 C99 之前,inline
不是 C 标准的一部分,但许多编译器——尤其是 GCC——将其作为扩展实现。然而,在 GCC 的情况下,inline
的语义与上述说明略有不同。
在 C99(及更新版本)中,没有链接规范的内联函数只是一个内联定义(“内联定义不为函数提供外部定义,也不禁止在另一个翻译单元中进行外部定义。 “§6.7.4p7)。但在 GCC 扩展中,没有链接规范的内联函数被赋予了外部链接(就像非内联函数声明一样)。 GCC 然后对 extern inline
进行特殊处理,表示“不生成函数对象”,这实际上与标准 C99 处理既没有 extern
也没有 static
修饰符。查看GCC manual ,尤其是最后一节。
这仍然很重要,因为 GCC 仍然默认使用其原始的 inline
语义,除非您指定它应符合某些 C 标准(例如,使用 -std=c11
) 或使用 -fno-gnu89-inline
禁用 GNU 内联语义。
据我所知,示例代码取自 IBM i7.1 编译器文档,并未正确反射(reflect)任何 C 标准。 foo
的两个定义作为内联函数不会生成任何名为foo
的实际函数,因此 &foo
的使用必须引用一些外部定义的foo
,程序中没有。如果您告诉 GCC 使用 C11/C99 语义,GCC 将报告此问题:
$ gcc -std=c99 a.c b.c
/tmp/ccUKlp5g.o: In function `g':
a.c:(.text+0xa): undefined reference to `foo'
a.c:(.text+0x13): undefined reference to `foo'
/tmp/cc2hv17O.o: In function `main':
b.c:(.text+0xa): undefined reference to `foo'
b.c:(.text+0x13): undefined reference to `foo'
collect2: error: ld returned 1 exit status
相比之下,如果您要求 Gnu 内联语义,两个翻译单元都会定义 foo
,并且链接器会提示重复定义:
$ gcc -std=c99 -fgnu89-inline a.c b.c
/tmp/ccAHHqOI.o: In function `foo':
b.c:(.text+0x0): multiple definition of `foo'
/tmp/ccPyQrTO.o:a.c:(.text+0x0): first defined here
collect2: error: ld returned 1 exit status
另请注意,默认情况下 GCC 不内联任何函数。您必须提供一些优化选项才能启用函数内联。如果这样做,并且删除了地址运算符的使用,则可以编译程序:
$ cat a2.c
#include <stdio.h>
inline int foo() { return 3; }
void g() {
printf("foo called from g: return value = %d\n", foo());
}
$ cat b2.c
#include <stdio.h>
inline int foo() { return 4; }
void g();
int main() {
printf("foo called from main: return value = %d\n", foo());
g();
return 0;
}
$ # With no optimisation, an external definition is still needed:
$ gcc -std=c11 a2.c b2.c
/tmp/cccJV9J6.o: In function `g':
a2.c:(.text+0xa): undefined reference to `foo'
/tmp/cct5NcjY.o: In function `main':
b2.c:(.text+0xa): undefined reference to `foo'
collect2: error: ld returned 1 exit status
$ # With inlining enabled, the program works as (possibly) expected:
$ gcc -std=c11 -O a2.c b2.c
$ gcc -std=c11 -O1 a2.c b2.c
$ ./a.out
foo called from main: return value = 4
foo called from g: return value = 3
如 IBM 文档所示,C++ 的规则是不同的。该程序不是有效的 C++,因为两个翻译单元中 foo
的定义不同,但编译器没有义务检测此错误,并且适用通常的未定义行为规则(即,标准不定义要打印的内容)。碰巧的是,GCC 似乎显示了与 i7.1 相同的结果:
$ gcc -std=c++14 -x c++ a.c b.c
$ ./a.out
foo called from main: return value = 3, address = 0x55cd03df5670
foo called from g: return value = 3, address = 0x55cd03df5670
关于澄清 C 中内联函数的内部链接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51533082/
我需要将文本放在 中在一个 Div 中,在另一个 Div 中,在另一个 Div 中。所以这是它的样子: #document Change PIN
奇怪的事情发生了。 我有一个基本的 html 代码。 html,头部, body 。(因为我收到了一些反对票,这里是完整的代码) 这是我的CSS: html { backgroun
我正在尝试将 Assets 中的一组图像加载到 UICollectionview 中存在的 ImageView 中,但每当我运行应用程序时它都会显示错误。而且也没有显示图像。 我在ViewDidLoa
我需要根据带参数的 perl 脚本的输出更改一些环境变量。在 tcsh 中,我可以使用别名命令来评估 perl 脚本的输出。 tcsh: alias setsdk 'eval `/localhome/
我使用 Windows 身份验证创建了一个新的 Blazor(服务器端)应用程序,并使用 IIS Express 运行它。它将显示一条消息“Hello Domain\User!”来自右上方的以下 Ra
这是我的方法 void login(Event event);我想知道 Kotlin 中应该如何 最佳答案 在 Kotlin 中通配符运算符是 * 。它指示编译器它是未知的,但一旦知道,就不会有其他类
看下面的代码 for story in book if story.title.length < 140 - var story
我正在尝试用 C 语言学习字符串处理。我写了一个程序,它存储了一些音乐轨道,并帮助用户检查他/她想到的歌曲是否存在于存储的轨道中。这是通过要求用户输入一串字符来完成的。然后程序使用 strstr()
我正在学习 sscanf 并遇到如下格式字符串: sscanf("%[^:]:%[^*=]%*[*=]%n",a,b,&c); 我理解 %[^:] 部分意味着扫描直到遇到 ':' 并将其分配给 a。:
def char_check(x,y): if (str(x) in y or x.find(y) > -1) or (str(y) in x or y.find(x) > -1):
我有一种情况,我想将文本文件中的现有行包含到一个新 block 中。 line 1 line 2 line in block line 3 line 4 应该变成 line 1 line 2 line
我有一个新项目,我正在尝试设置 Django 调试工具栏。首先,我尝试了快速设置,它只涉及将 'debug_toolbar' 添加到我的已安装应用程序列表中。有了这个,当我转到我的根 URL 时,调试
在 Matlab 中,如果我有一个函数 f,例如签名是 f(a,b,c),我可以创建一个只有一个变量 b 的函数,它将使用固定的 a=a1 和 c=c1 调用 f: g = @(b) f(a1, b,
我不明白为什么 ForEach 中的元素之间有多余的垂直间距在 VStack 里面在 ScrollView 里面使用 GeometryReader 时渲染自定义水平分隔线。 Scrol
我想知道,是否有关于何时使用 session 和 cookie 的指南或最佳实践? 什么应该和什么不应该存储在其中?谢谢! 最佳答案 这些文档很好地了解了 session cookie 的安全问题以及
我在 scipy/numpy 中有一个 Nx3 矩阵,我想用它制作一个 3 维条形图,其中 X 轴和 Y 轴由矩阵的第一列和第二列的值、高度确定每个条形的 是矩阵中的第三列,条形的数量由 N 确定。
假设我用两种不同的方式初始化信号量 sem_init(&randomsem,0,1) sem_init(&randomsem,0,0) 现在, sem_wait(&randomsem) 在这两种情况下
我怀疑该值如何存储在“WORD”中,因为 PStr 包含实际输出。? 既然Pstr中存储的是小写到大写的字母,那么在printf中如何将其给出为“WORD”。有人可以吗?解释一下? #include
我有一个 3x3 数组: var my_array = [[0,1,2], [3,4,5], [6,7,8]]; 并想获得它的第一个 2
我意识到您可以使用如下方式轻松检查焦点: var hasFocus = true; $(window).blur(function(){ hasFocus = false; }); $(win
我是一名优秀的程序员,十分优秀!