【问题标题】:C mutually referencing static initializersC相互引用静态初始化器
【发布时间】:2012-10-02 21:26:42
【问题描述】:

C 中是否可以有相互引用的静态变量初始化器,如下例所示?

如果将第 2 行添加到预先声明的“B”中,则该示例将在 gcc -Wall 中编译,而不会发出警告。第 2 行令人讨厌,因为它也定义了 B,第 4 行也是如此。带有 -weak 检查的 splint lint 程序警告“B”被定义了两次:“变量 B 重新定义。函数或变量被重新定义。一个的声明应该使用 extern。"

通常会使用 extern 关键字进行声明,但 extern 和 static 不能一起使用,并且在 gcc 下无法编译。

#include <stdio.h>                               /*1*/
volatile static void * B;                        /*2*/
volatile static void * A = &B;                   /*3*/
volatile static void * B = &A;                   /*4*/
int main()                                       /*5*/
{                                                /*6*/
    printf("A = %x, B = %x\n", (int)A, (int)B);  /*7*/
    return 0;                                    /*8*/
}                                                /*9*/

谢谢

【问题讨论】:

  • 我想知道你为什么需要这个?
  • 这是一个简化的例子。在我的嵌入式应用程序中,这项技术初始化了一个显示在 20x4 LCD 显示器上的菜单链接列表。每个菜单都有指向相邻导航菜单的指针。
  • 抛开非问答题不谈,将菜单存储在数组中并通过索引而不是指针链接是否更简单?
  • 听起来像夹板不理解暂定定义。我建议您向开发人员提交错误报告。

标签: c gcc static initialization


【解决方案1】:

尽管volatile 相对于static 的位置很奇怪,但您发布的代码是完全有效的C。它使用称为暂定定义的特定于C 的功能。此功能确保您的程序中只有一个BB 的两个定义定义了相同的实体。没有什么“令人反感”的。

您从夹板收到的警告无效。在 C++ 语言中,这确实会构成多定义错误,但在 C 中不会。关于 extern 的评论在 C 语言的上下文中毫无意义。

【讨论】:

  • K&R2 (A10.2) 仅为外部对象定义暂定定义,而不是静态定义。然而,较新的 ISO 规范通过明确允许静态变量的暂定定义来支持这个答案。
  • @ab:我确定不是这样的。您在这种情况下误解了“外部”一词的含义。 “外联”不代表外联。原始 ANSI C89/90(我敢肯定,在 K&R2 中)的“6.7.2 外部对象定义”标题中的“外部”一词指的是在函数之外进行的定义,在文件范围中。在这种情况下,“外部”仅表示 非本地。 C89/90 中的 6.7.2 明确允许对使用 static 声明的对象进行暂定定义。尽管在 1988 年发布,K&R2 与 C89/90 同步,所以它应该说明同样的事情。
【解决方案2】:

这是没有意义的。

编辑:

是的,'extern' 中不需要(谢谢,AndreyT 和 Adam Rosenfield),但 &amp;B 的类型是 void**,而不是 void*

当然,void** 转换为 void*,但有什么意义呢?如果你想要别名或指针,那么只需声明第三个变量“缓冲区”,并在 A 和 B 中指向它。

unsigned char SomeBuffer[LENGTH];

void* A = SomeBuffer;
void* B = SomeBuffer;

【讨论】:

  • extern 会给它外部链接而不是内部链接。这不是重新声明,它实际上是所谓的暂定定义,它是完美的C。
  • extern 可能有助于实现什么?代码完全有效。
  • @AndreyT:我不知道 OP 真正想要实现什么,所以我建议指向一些实际的容器。 “extern”关键字没有用,我会修复答案。
【解决方案3】:

看起来您正在定义一个循环循环,但实际上并非如此。 C &amp; 运算符是 address-of 运算符并获取相关变量的地址。

正如@AndreyT 所指出的,第 2 行具有暂时定义B 的效果,以便第 3 行知道它。您可以认为第 2 行为 B 分配内存位置,然后在第 4 行中输入一个值。

代码在功能上与您编写的代码相同:

volatile static void * A;
volatile static void * B;
int main()
{
    A = &B;
    B = &A;
    printf("A = %x, B = %x\n", (int)A, (int)B);
    return 0;
}                    

因此,在第 3 行中,您将 A 定义为指向 B 的地址。在第 4 行中,您将B 定义为指向A 的地址。

假设AB 具有以下内存地址:

&A == 0xAAAAAAAA
&B == 0xBBBBBBBB

第 3 行中的代码执行以下操作:

A = 0xBBBBBBBB;

然后在第 4 行执行以下操作:

B = 0xAAAAAAAA;

现在,如果您要取消引用 AB,您将得到以下结果(注意,您必须先转换为可取消引用的指针类型):

*A --> 0xAAAAAAAA
*B --> 0xBBBBBBBB

这是完全有效的,但可能不是您打算对代码执行的操作。

请记住,有两个不同的价值观在起作用。首先是指针的值。其次是指针的地址。

您需要使用extern 的唯一原因是使用在另一个目标文件中定义的变量(即在file1.c 中您想使用在file2.c 中定义的全局变量)。 static 关键字应用于全局变量时意味着该变量是 file-static 或者它只能在该文件中使用。所以这两者显然是不和的。

【讨论】:

    猜你喜欢
    • 2011-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-31
    • 1970-01-01
    • 2021-07-12
    相关资源
    最近更新 更多