【问题标题】:Is there a way to make a variable survive 1 scope out of the current one?有没有办法使变量在当前范围之外的 1 个范围内存活?
【发布时间】:2019-10-11 21:03:24
【问题描述】:

我想创建一个返回指向本地定义变量的指针的函数。为了论证,我将调用函数struct awesome *makeCoolStruct()(我不想在应该调用struct awesome coolness = makeCoolStruct();的外部范围内声明变量,因为该函数将在多个地方被调用)。

我明白为什么当我尝试这样做时编译器会出错 - 一旦程序退出该范围,局部变量就会被“销毁”,所以指针基本上是无效的。

我查看了如何在函数中返回指向局部变量的指针,虽然我明白为什么malloc 会起作用,但这违背了尝试这样做的目的,因为malloc,就我了解,只要程序运行,就保留变量 - 或者直到调用 free。但是,这意味着我必须在调用我的函数的任何内容的末尾调用free。那时,我最好在每个调用范围内声明该变量,然后像 makeCoolStruct(&existingVariable); 一样传递一个指向它的指针。

但是,如果有一种方法可以声明“将此变量保留在堆栈中的更高位置”(这显然会在全局范围内产生编译错误,因为堆栈中没有更高的位置),那么我可以返回一个指针,只要我需要它,它就会一直存在,无论我决定调用struct awesome x = makeCoolStruct(); (我知道可变性问题 - 我不是在寻找可变性)。从那时起,我可以真正在函数中返回任何我想要的东西,而不仅仅是传入的东西。

我还没有真正尝试过任何东西,因为我不知道有什么可行的方法。

我希望能够在执行任何使变量保持更高范围的任何操作后返回指向局部变量的指针,而无需在调用函数时为函数调用做任何准备(创建一个变量供其使用输出而不是仅仅将输出分配给某物。

【问题讨论】:

  • 你可以在调用函数中创建变量并将其地址传递给被调用函数吗?你不会退回它,但它仍然会被修改。
  • 传递指针是通常的方式。没有办法用范围做你想做的事。
  • 实际上,您所说的并不是真正的作用域,而是生命周期。范围是指可以使用变量名称的地方,生命周期是指可以使用值的时间。它们是相关的,但不是一回事。
  • @Liran AFAIK 您需要手动管理内存并使用free(),之前声明一个变量,或者直接返回结构。所有这些方法都不起作用吗?
  • @Barmar 这是否意味着在分配时,程序会将结构复制过来?我正在使用一个 8Mhz 微控制器,所以我需要我能得到的所有性能优化——我敢打赌,在一个运行超过 100 次/秒的循环中复制一个由 80 个 2 字节结构组成的数组会导致巨大的性能损失。我试图避免在更高的范围内保留 6 个 80 个 2 字节结构的数组以节省 RAM(我们在这里谈论的是近 1kb)。

标签: c pointers lifetime scoping


【解决方案1】:

您的要求在 C 中是不可能的,但这里有一些替代方案:

传入堆栈变量:

typedef struct {
    int a;
    int b;
} Foo;

void bar(Foo* foo)
{
    foo->a = 5;
}

int main(void)
{
    Foo foo = {0};
    bar(&foo);
    return 0;
}

直接返回结构体:

Foo bar(void)
{
    Foo foo = {1, 2};
    return foo;
}

int main(void)
{
    Foo foo = bar();
    return 0;
}

手动管理内存

Foo* bar(void)
{
    Foo* foo = malloc(sizeof(*foo));
    return foo;
}

int main(void)
{
    Foo* foo = bar();
    free(foo);
    return 0;
}

最后,如果你真的不喜欢谁来继承这个项目,你总是可以使用宏:

#define FOO(X)     \
    Foo X = {0};   \
    bar(&X);

【讨论】:

  • 问题中提到了第一种方法,他只是在寻找替代方法。
  • 我已经想到但不想使用的两个选项......叹息......
  • 对,宏哈哈哈,如果我感觉邪恶哈哈哈!我想他们可以工作......你的答案现在非常全面!太棒了,有很多不同的方法来解决它(尤其是我以前没有想到的宏)
【解决方案2】:

虽然不推荐,但实际上返回指向静态变量的指针是安全的,前提是您的程序不是多线程的。

struct myStruct {
    int x;
    char y;
};

struct myStruct *foo() 
{
    static struct myStruct bar = {.x = 0, .y = 'a'};
    return &bar;
}

我永远不会写这样的东西,但它是安全的,因为它不会调用未定义的行为。

以防万一您不知道,返回一个结构非常酷。你不需要 malloc 。这样就好了:

struct myStruct foo() 
{
    struct myStruct bar = {.x = 0, .y = 'a'};
    return bar;
}

【讨论】:

  • 在多线程程序中使用static 局部变量是不安全的,或者(至少)它会限制函数在多线程程序中的有用性。这也意味着您不能同时保存两个值。将指向结构的指针传递给函数或返回结构值(不是指针)通常是最佳选择。
  • 我的程序不是多线程的,但无论哪种方式使用像这样的静态方法对我来说都感觉非常非常肮脏。我讨厌这个主意。
  • @JonathanLeffler 是的。我忘了多线程。答案已更新。
  • ISR 的问题与多线程系统的问题相同。虽然这是一种有缺陷的方法,最好避免,但它是一种合法的方法,需要提及并且在其他答案中缺失。
猜你喜欢
  • 2010-10-20
  • 1970-01-01
  • 2017-07-20
  • 1970-01-01
  • 2012-01-11
  • 2021-08-18
  • 1970-01-01
  • 2020-06-18
相关资源
最近更新 更多