静态内联函数和普通void函数有什么区别?

17
我正在使用C语言并修改之前由其他人编写的代码。我遇到了一些问题,并尽可能地了解了正在发生的事情。因此,正如我的问题所述,当创建函数时,static inline voidvoid之间有什么区别?提前为冗长的文章道歉,但我希望您知道我做了一些研究,但不理解我找到的内容。
我在这里找到一个关于static的解释,但它让我感到困惑:
“static”说明符表示无法从其他文件引用该函数;也就是说,链接器不会导出该名称。
通过阅读此内容,我认为引用函数与调用函数不同?我之所以这么认为,是因为从另一个.c文件中调用了此函数。如果是这种情况,那么引用函数是什么意思?
通过同一网站,他们解释了内联函数,我不明白它是什么意思。
“__inline”关键字告诉编译器替换函数定义中的代码以代替每个函数调用实例。然而,替换仅在编译器自己的判断下发生。例如,如果函数的地址被取出或者需要替换太大,编译器就不会对其进行内联处理。
什么??
非常感谢任何帮助,并再次为这篇可怕的长文章道歉。
下面的内容位于file1.c中(使用通用名称,因为我认为这并不重要)。
COMPLEX cNoiseSample;
CGauss( &cNoiseSample, loopbackRadio->pState );

以下内容位于file2.c文件中

static inline void CGauss( COMPLEX * pcGauss, P_OS_UNIFORM_RAND_STATE pState )
{
    //code
}
6个回答

17

static 表示它不能从另一个编译单元(源文件)引用。 "引用" 意味着被调用或以其他方式按名称引用,例如分配给函数指针。

inline 是向编译器发出提示,函数的代码应在调用它的位置内联生成,而不是生成为要分支到的单独函数。这通常是出于性能原因而这样做的。对于Microsoft的引述:

  

如果函数的地址被使用或者函数太大而无法内联,则编译器不会将函数内联。

内联函数没有地址,因为它不作为单独的实体存在。其代码与调用它的代码无缝交织在一起。因此,如果取函数的地址(例如赋值给指针),则编译器必须将其生成为一个实际的函数,并且无法内联它。

void 表示该函数不返回值。


看了您的代码示例,我猜测 CGauss() 有一个单独的定义,在file1.c 中被调用,而 file2.c 调用自己私有版本的函数。要么是这样,要么是 file1.cfile2.c 中使用了 #include,这是不好的做法。


此外,当一个函数在不同的编译单元中包含头文件时(至少在C++中是这样),需要使用inline来强制执行一次定义规则(我不确定C语言的细节是否相同)。 - rubenvb
我想我比@Graham-Borland有点困惑。让我向您展示原因:COMPLEX cNoiseSample; CGauss(&cNoiseSample,loopbackRadio->pState); /此代码在.c源文件的某一点被调用,在另一个.c源文件中,我有这个:/ static inline void CGauss(COMPLEX * pcGauss,P_OS_UNIFORM_RAND_STATE pState)/我为注释框中的格式不佳道歉,不确定如何处理。/ - TZPike05
它正在#include它。在这段代码中有很多这样的东西。处理大约200-250个源文件和相同数量的头文件(必须喜欢在别人的代码上工作:))甚至没有考虑#include函数是它能够正常工作的原因。 - TZPike05
1
为什么你应该使用static:作为一个通用的经验法则,如果你大量使用static,你的代码将会更容易维护。它告诉维护者“你可以自由地更改这个函数而不会破坏文件外的任何东西”。任何不是静态的符号(函数或变量)都可以从任何地方引用。如果你碰巧来自面向对象的语言(C++、Java等),那么请将static函数(或全局变量)视为private,其他所有内容视为public。此外,使用static函数可以进行更积极的编译器优化。 - Brian McFarland
虽然static函数不能直接从其他翻译单元调用,但您可以传递一个指向static函数的函数指针到另一个翻译单元,并从那里调用这些函数。 - 12431234123412341234123

9

static 只有在你有多个源文件时才具有意义。它指定 static 函数或变量不能从不同文件中的函数访问。

inline 是编译器优化,可以在某些情况下加速代码。每当您调用一个函数时,都会涉及一些开销。因此编译器可以通过复制+粘贴(几乎)内联代码来消除函数。

以下是内联示例:

int dotproduct(int x1, int y1, int x2, int y2) {
    return multiply(x1,x2)+multiply(y1,y2);
}

inline int multiply(int a, int b) {
    return a*b;
}

编译器将把此代码转化为:
int dotproduct(int x1, int y1, int x2, int y2) {
    return x1*x2+y1*y2;
}

如果你想更加高级,你也可以内联使用点积函数 ;)
请注意,inline关键字只是提示编译器内联某些函数。它可能会或可能不会根据自己的判断实际执行。

感谢@tskuzzy,现在inline更有意义了。 - TZPike05

3

静态关键字

C语言中定义一个静态函数意味着 (正如文档所述) 这个函数只能从定义它的源文件中访问。在这种情况下,“引用”一词既可以指调用此函数,也可以指获取对其的函数指针。

内联

通常,在C语言中编写函数时,编译器会生成该函数的机器码:

foo:
   /* some machine code */
   ret

每次调用此函数时,编译器会插入一个指令,例如

  call <foo>

将代码嵌入到调用方的机器码中,这意味着“跳转到foo函数,执行那里的内容,并在遇到ret指令时返回到此位置”。

相比之下,对于内联函数,编译器不会生成一个单独的foo()函数,而是将函数foo的机器码插入到每个调用点。执行此代码时,将产生相同的效果。

为什么要这样做呢?内联代码的优点是可以节省两个跳转(调用和相应的ret),从而使您的代码执行速度更快。缺点是代码会变大,因为您在每个调用点上插入机器码,而不是只有一个可调用函数的副本。因此,通常只内联小型函数。

此外,您无法针对内联函数使用函数指针,调试也变得更加困难,因为您不能轻松地在内联函数上设置断点。

因此,将内联留给编译器作为一种优化选项,并使用关键字(例如C++的inline)或GCC的__attribute__((inline))等指令,您只是给编译器暗示,在这里尝试内联可能值得一试。


1

在阅读以上内容之前,我希望您能够了解C编程的工作原理。 如果您只是简单地编写开放式代码,例如:

Setup(){
    int MainVar
}

MyRoutine(){
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

然后,任何人都可以直接从第二个程序访问MyRoutine.myVar1。如果它没有受到保护,如果他们知道它的存在并且知道它的作用,他们可以在其在MyRoutine // Do stuff中使用之前更改myVar2的值,从而改变原始程序员的意图。
想象一下,你正在编写一个银行程序,并留下了代码漏洞,以便有人可以在不改变例程中其他银行的WITHDRAWL的情况下更改DEPOSIT的价值。其他人可以编写一个单独的程序来将该值更改为2或10,并在不存在资金的情况下创造资金。但是,如果您在代码、例程、方法或变量之前加上STATIC,则这些项目无法被另一个程序访问、查看和最重要的是更改。
您可以在任何时候使用Static,使整个例程关闭,或仅关闭单个变量。从而允许其他人对代码的某些方面进行更改,但保留需要受保护的方面。
将Static放在MyRoutine中将防止某人从另一个程序执行MyRoutine。由于MyVars在MyRoutine内声明,因此它们将无法从另一个程序访问。但是,如果在程序的其他地方声明了一个名为MainVar的变量,则该变量将可访问。
Setup(){
    int MainVar  // This can be accessed from outside this code
}

static MyRoutine(){  // Because of static these vars are not
   int myVar1;
   int myVar2;
   bool myVar3;
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

在这里,只有带有static的变量受到保护。myVar3可以从其他地方读取,通知另一个程序交换已经完成。

Setup(){
    int MainVar    // This can be accessed from outside this code
}

MyRoutine(){
   static int myVar1;  // This can NOT be accessed from outside this code
   static int myVar2;  // This can NOT be accessed from outside this code
   bool myVar3;        // This can be accessed from outside this code
   // Do stuff with myVars
   MainVar = myVar1 - myVar2;
   myVar3 = true;
}

0

static 的意思是,该函数在定义它的源文件之外基本上是“不可见”的。

inline 要求编译器在编译时将函数调用代码直接替换为函数代码,就像用函数代码替换函数调用一样 - 但是,不能保证这种情况发生,它只是向编译器建议。

实际上比这更技术化,你可能会得到一个更好的答案,但用简单的语言来说,这就是这些术语的含义。


-2

这很简单。

void* 可以返回一个 void 指针(任何引用)。 但是 void 不能返回任何东西。

例如:

1)

int x=7;

void *abc()    
{    
    return &x;    
}     

int main()    
{    
    printf("%d\n",*((int*)(abc())));    
}

输出:7

2)

int x=7;

void abc()    
{    
    return &x;    
}

int main()    
{    
    printf("%d\n",*((int*)(abc())));    
}

printf("%d\n",*((int*)(abc())));处会产生编译错误。

因为void无法返回任何内容。


请将 "printf("%d\n",((int)(abc())));" 替换为 "printf("%d\n",*((int)(abc())));", 这是一个打字错误。 - pawanesh kumar pal

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接