如何在C语言中两个函数之间共享变量?

3

在C语言中,假设var1是foo1()函数中的一个变量,而foo2()想要访问var1,但是foo1()没有调用foo2(),因此我们无法通过参数传递它。同时,只有foo1()和foo2()会访问它,因此我不想将其声明为全局变量。这类似于C++中的“友元语义”,那么在C语言中有没有实现这种功能的方法呢?

void foo1() {
  ... 
  var1;
  ....
}


void foo2() {
 ...
 how to access var1?
 ...
}

1
“Friend” 的概念与类和私有/受保护成员相关。在函数中,您只能使用全局变量。http://www.codingunit.com/c-tutorial-functions-and-global-local-variables - Darth Hunterix
1
还有一种方法没有在他们的答案中强调,那就是静态全局变量的概念。通常情况下我不会推荐使用,但在C语言中,在一个C文件内,如果你声明了static int var1; 那么它只能被该文件内的函数访问到。所以,如果你有一个foos.c文件和两个foo函数,两个函数都可以访问var1,而文件外的任何东西都不能使用它。这仍然不是很好,但它限制了全局变量的作用域。基本上,在C语言中,公共/私有/友元不是受支持的概念,它基本上就像一个大杂烩,任何人都可以混在一起。 - Keith Nicholas
@KeithNicholas 是的,我认为静态全局变量可以行。 - notbad
我建议通常不要使用它,因为它往往会使C代码难以维护/更改。 - Keith Nicholas
@ryyker 我绝对不会推荐那种做法。如果你需要这样的东西,我建议使用一个静态全局变量,然后编写一个"getter 函数" int getVar1(),并将其放入头文件中返回该静态全局变量。 - Keith Nicholas
@KeithNicholas - 我只是在回应OP给出的标准:1) foo1()foo2() 不相互调用。 2) 没有任何函数参数。我实际上很喜欢你的 struct * 方法。我经常这样做来避免在项目前端修改参数列表以避免参数列表不断增长。(无论我们添加多少成员,struct *a 都始终是 struct *a)。但考虑到OP的指导方针,我提出了这个想法。谢谢。 - ryyker
6个回答

6
你把变量传递给两个函数....通常来说,函数不应该保存状态。
很快你会发现传递变量并不是那么好,而且变得很脆弱,所以你可以传递结构体....然后函数开始对结构体的状态进行操作。
typedef struct 
{
    int var1;
} blah_t;

void foo1(blah_t* b)
{
    b->var1=0;
}

void foo2(blah_t* b)
{
    b->var1++;
}

这是进行面向对象C编程的非常简单的基本想法。

我认为blah_t是保留的... 我猜只有在POSIX中。 - Grady Player

2

您需要在函数作用域之外声明 var1 ,然后将其作为参数发送给两个函数。或者,将其声明为全局变量。


1
按引用传递是一种方式:(在此示例中,变量的内存仅局限于caller()
void caller()
{
    int i = 5;
    foo(&i);
    bar(&i);
    printf("\n final i is %d",i);
}

void foo(int *i)
{
    printf("%d",*i);
    *i += 5;
}

void bar (int *i)
{
    printf("%d",*i);
    *i += 5;
}

全局变量:(通常被认为是可怕的 i 应该有一个更像 GLOBAL_I 的名称或类似的东西)

int i = 0;

void caller()
{
   i=5;
   foo();
   bar();
   printf("\n final i is %d",i);
}

void foo()
{
   printf("%d",i);
   i += 5;
}

 void bar (int i)
 {
      printf("%d",i);
      i += 5;
 }

你忘记在 i += 5 后面加分号了。 - Étienne

1
关于C++中的“友元语义”,C语言没有相同的功能。
关于“因此我们无法通过参数传递它”的问题。在C语言中,访问函数之间的变量的唯一选项是使用某种类型的全局变量。
如果您想要在不同的C模块中存在void foo1()void foo2(),但仍希望能够访问相同的变量,并确保其值在项目的所有位置始终相同,则考虑使用extern scope
在一个对于(多个)模块都通用的头文件中,可以实现一个“项目范围全局”变量,方法如下。

file.h

void foo1(void);
void foo2(void);
extern int var1;  

file1.c

#include "file.h"
int var1 = 5; //in only 1 module, declare and initialize the 
              //extern defined in the common header -file.h-

int main(void)
{
    printf("value of var1 is %d\n", var1);//original value of var1
    foo1();
    printf("value of var1 is %d\n", var1);//var1 modified by foo1()
    foo2();
    printf("value of var1 is %d\n", var1);//var1 modified by foo2()
    return 0;
}

void foo1(void)
{
    var1 = 15;//Now that the project global variable
              //has already been declared and defined, it can simply
              //be used, in this file...   
}

file2.c

#include "file.h"

void foo2(void)
{
    var1 = 20;... and in this one
}

0
不行。变量只在函数栈上存在,而 foo1() 正在运行时才存在。当离开函数时,栈就会消失。你可以将变量设置为静态以保持其存活,但这样你也无法在没有 hack 的情况下从外部访问它。

-1

这个答案受到了许多其他语言中的“模块”概念的启发,可以使用gcc的嵌套函数来近似。变量var1foo1()foo2()中都在作用域内,但对于其他所有内容都不在作用域内。该解决方案既不使用全局变量也不使用参数。

void foo(int fn)
{
    static int var1;

    void fn1(void)
    {
        var1 = 15;
    }

    void fn2(void)
    {
        var1 = 20;
    }

    (fn == 1)? fn1(): fn2();
    printf("Value of var1 is now %d\n", var1);
}

void foo1(void){foo(1);}
void foo2(void){foo(2);}

int main (void)
{
    foo1();
    // Expected stdout: Value of var1 is now 15

    foo2();
    // Expected stdout: Value of var1 is now 20
}  

你确定这行代码 foo((fn == 1)? fn1(): fn2()); 没有问题吗? - Michi
你修改了你的答案,这很好,但是即使如此,你仍然有一个“变量'var1'设置但未使用”的问题。 - Michi
@Michi - 是的,这段代码只是回答了最初的问题,即两个函数可以独占地“看到”一个共同的变量,但其他函数不能。但为了你,我会添加一个实际使用var1的printf()。 - Potion
这确实是一个糟糕的模式。 - Antti Haapala -- Слава Україні

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