我有一个我需要宏功能的功能.该函数包含临时变量,我不记得是否有关于在宏替换中使用临时变量的规则.
long fooAlloc(struct foo *f, long size)
{
long i1, i2;
double *data[7];
/* do something */
return 42;
}
Run Code Online (Sandbox Code Playgroud)
MACRO表格:
#define ALLOC_FOO(f, size) \
{\
long i1, i2;\
double *data[7];\
\
/* do something */ \
}
Run Code Online (Sandbox Code Playgroud)
这个可以吗?(即没有令人讨厌的副作用 - 除了通常的那些:不是"类型安全"等).顺便说一句,我知道"宏是邪恶的" - 在这种情况下我只需要使用它 - 没有多少选择.
我inline在C99 感到困惑.
这就是我想要的:
.c文件).static inline).C++就是inline这样做的.
但是(如果我错了请纠正我)在C99中没有办法得到这种行为.
我可以使用static inline,但它会导致重复(不同翻译单元中相同功能的地址不一样).我不希望这种重复.
所以,这是我的问题:
inlineC99的理念是什么?参考文献:
inline,但我不明白为什么.这只"仅在一个编译单元中"限制真的那么好吗?inline.我读过它,但我不明白.inline函数的策略.inline在C99中获得C++ 行为(是的,我们可以)head.h
#ifndef __HEAD_H__
#define __HEAD_H__
inline int my_max(int x, int y) {
return (x>y) ? (x) : (y);
}
void call_and_print_addr();
#endif
Run Code Online (Sandbox Code Playgroud)
src.c
#include "head.h"
#include <stdio.h>
// This is necessary! And it should occurs and only occurs …Run Code Online (Sandbox Code Playgroud) 我正在重构一些C代码并对因子部分进行单元测试(使用Google Test).在循环中多次使用了一个片段,因此为了将其暴露给测试,我将其作为inline头文件中的函数进行了考虑,该头文件demo.h还包括一些其他非inline函数的声明.简化版如下:
#ifndef DEMO_H_
#define DEMO_H_
#ifdef __cplusplus
extern "C" {
#endif
inline void print_line(FILE* dest, const double * data, int length) {
for (int s = 0; s < length; s++)
fprintf(dest, "%lf ", data[s]);
fprintf(dest, "\n");
}
#ifdef __cplusplus
}
#endif
#endif /* MK_H_ */
Run Code Online (Sandbox Code Playgroud)
我的测试代码
#include "gtest/gtest.h"
#include "demo.h"
#include <memory>
#include <array>
#include <fstream>
TEST (demo, print_line) {
std::array<double,4> test_data = {0.1, 1.4, -0.05, 3.612};
const char* testfile = "print_line_test.txt"; …Run Code Online (Sandbox Code Playgroud) 如果我有:
inline int foo(void)
{
return 10 + 3;
}
int main(void)
{
foo();
}
Run Code Online (Sandbox Code Playgroud)
使用GCC,文件编译得很好,但链接器返回 undefined reference to foo
相反,如果我删除inline链接器很高兴!
看起来链接器可以看到外部定义的标识符,但内联定义的标识符不是.
此外,如果我使用-O3标志编译,链接器将看到内联定义的标识符.
有什么问题?
那么,标准无法保证inline函数实际内联; 必须使用宏才能获得100%的保证.无论inline关键字如何,编译器总是根据自己的规则决定哪个函数内联或不内联.
那么,inline当使用现代编译器(如最新版本的GCC)时,关键字何时会对编译器的作用产生什么影响?
我想在代码中引入一个弱符号,但是,当使用* .a文件时,我无法理解它的行为。
这是我的最小示例:
文件啊:
void foo() __attribute__((weak));
Run Code Online (Sandbox Code Playgroud)
文件ac:
#include "a.h"
#include <stdio.h>
void foo() { printf("%s\n", __FILE__); }
Run Code Online (Sandbox Code Playgroud)
文件BC:
#include <stdio.h>
void foo() { printf("%s\n", __FILE__); }
Run Code Online (Sandbox Code Playgroud)
文件main.cpp:
#include "a.h"
#include <stdio.h>
int main() { if (foo) foo(); else printf("no foo\n"); }
Run Code Online (Sandbox Code Playgroud)
现在,根据我使用* .o文件(make -c a.c和make -c b.c)还是* .a文件(ar cr a.o和ar cr b.o),输出是不同的:
1)g++ main.cpp a.o b.o打印bc
2)g++ main.cpp b.o a.o打印bc
3)不g++ main.cpp a.a b.a …
执行cc -std=c99 example.c以下简化example.c文件:
inline void a()
{
}
int main()
{
a();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
得到我:
在函数`main'中:
example.c :(.text + 0x7):未定义引用'
a'collect2:ld返回1退出状态
据我所知,这与C99标准的要求有关,要求在无法内联的情况下使用的每个内联非静态函数的另一个定义?如果是这样的话,我猜我可以这样做static inline,但我不想让它在以后咬我,那么这里最好的做法是什么呢?显然,我想坚持C99,我想内联一些功能.(是的,我知道编译器通常知道什么内联而不被告知,但我有我的理由)
我正在尝试用内联函数替换一些宏子程序,因此编译器可以优化它们,因此调试器可以进入它们,等等.如果我将它们定义为普通函数,它可以工作:
void do_something(void)
{
blah;
}
void main(void)
{
do_something();
}
Run Code Online (Sandbox Code Playgroud)
但如果我将它们定义为内联:
inline void do_something(void)
{
blah;
}
void main(void)
{
do_something();
}
Run Code Online (Sandbox Code Playgroud)
它说"错误:未定义的外部".那是什么意思?在黑暗中刺了一下,我试过了
static inline void do_something(void)
{
blah;
}
void main(void)
{
do_something();
}
Run Code Online (Sandbox Code Playgroud)
没有更多的错误.函数定义和对函数的调用都在同一个.c文件中.
有人可以解释为什么一个有效,另一个没有?
(第二个相关问题:如果我想在多个.c文件中使用它们,我在哪里放入内联函数?)
我已经阅读了很多关于在头文件中使用static inline和inline定义函数的文章,以便跨多个翻译单元进行访问.inline由于有外部联系,似乎是正确的方法.
我的问题是inline在.h文件中定义函数时使用说明符导致的结果代码大小:
生成的代码扩展是否inline仍然比引起的更小static inline?
为什么extern inline在相应的.c文件中需要声明?
使用gcc或时clang,启用多个警告通常是一个好主意,第一批警告通常由 提供-Wall。该批次相当大,并且包含特定警告-Wunused-function。
现在,-Wunused-function可用于检测static不再调用的函数,这意味着它们无用,因此最好从源代码中删除。当实行“零警告”政策时,它不再是“可取的”,而是彻头彻尾的强制性。
出于性能原因,某些函数可能会直接定义到头文件中*.h,以便可以在编译时内联它们(忽略任何类型的 LTO 魔法)。此类函数通常声明和定义为static inline。static inline在过去,此类函数可能会被定义为宏,但只要适用,最好将它们改为函数(没有有趣的类型问题)。
好的,出于性能原因,现在我们将一堆函数直接定义到头文件中。包含此类头文件的单元没有义务使用其所有声明的符号。因此,static inline头文件中定义的函数可能不会被调用。
对于gcc,那很好。gcc会标记一个未使用的static函数,但不会标记一个inline static。但clang结果是不同的:如果单个单元不调用static inline标头中声明的函数,则会触发警告。-Wunused-function而且不需要很多标志就可以到达那里:-Wall就足够了。
解决方法是引入特定于编译器的扩展,例如__attribute__((unused)),它向编译器明确声明标头中定义的函数不一定会被其所有单元调用。好的,但是现在,曾经干净的代码C99包含某种形式的特定编译器扩展,增加了可移植性和维护的重量。
因此,问题更多地是关于这种选择的逻辑:为什么当未调用标头中定义的函数clang时 selects 会触发警告?static inline在什么情况下这是一个好主意?
什么clang建议涵盖头文件中定义的内联函数的相对常见情况,而不要求使用编译器扩展?
编辑:经过进一步调查,问题似乎不正确。使用应用选定列表编译标志(等)的 linter在编辑器(VSCode)中触发警告。但是,当实际使用完全相同的标志列表编译源代码时,不会出现“未使用的函数”警告。clang-Wallclang
到目前为止,编辑器中可见的结果与编译时找到的结果完全相同。这是我第一次目睹差异。
因此,问题似乎与 linter 用于clang生成警告列表的方式有关。这是一个更加复杂和具体的问题。
请注意 …