C相互引用的静态初始值设定项

C相互引用的静态初始值设定项,c,gcc,static,initialization,C,Gcc,Static,Initialization,在C中是否可能有相互引用的静态变量初始值设定项,如下面的示例所示 如果将第2行添加到预声明“B”,则该示例将编译,而gcc-Wall中没有警告。第2行令人讨厌,因为它也定义了B,第4行也是如此。splint lint程序使用-weak检查警告“B”定义了两次:“变量B已重新定义。函数或变量已重新定义。其中一个声明应使用extern。” 通常使用extern关键字进行声明,但extern和static不能一起使用,并且不能在gcc下编译 #include <stdio.h>

在C中是否可能有相互引用的静态变量初始值设定项,如下面的示例所示

如果将第2行添加到预声明“B”,则该示例将编译,而gcc-Wall中没有警告。第2行令人讨厌,因为它也定义了B,第4行也是如此。splint lint程序使用-weak检查警告“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*/
#包括/*1*/
挥发性静态空隙*B/*2*/
挥发性静态空隙*A=&B/*3*/
挥发性静态空隙*B=&A/*4*/
int main()/*5*/
{                                                /*6*/
printf(“A=%x,B=%x\n”,(int)A,(int)B);/*7*/
返回0;/*8*/
}                                                /*9*/
谢谢

这是毫无意义的

编辑:

是的,不需要“外部”(谢谢,AndreyT和Adam Rosenfield),但是
&B
有一种
void**
,而不是
void*

当然,
void**
强制转换为
void*
,但这有什么意义呢?如果希望别名或指针相互指向,那么只需声明第三个变量“缓冲区”,并在a和B中指向它

unsigned char SomeBuffer[LENGTH];

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

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


从夹板上得到的警告无效。在C++语言中,这将构成一个多定义错误,但在C中却不是这样。关于<代码> ExtNe>代码>的注释在C语言的上下文中毫无意义。

< P>它看起来像是定义了一个循环循环,但实际上你不是。C
&
运算符是运算符的地址,并获取相关变量的地址

正如@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;
}                    
A = 0xBBBBBBBB;
B = 0xAAAAAAAA;
因此,在第3行中定义
A
以指向
B
的地址。第4行定义
B
指向
A
的地址

假设
A
B
具有以下内存地址:

&A == 0xAAAAAAAA
&B == 0xBBBBBBBB
第3行中的代码执行以下操作:

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;
}                    
A = 0xBBBBBBBB;
B = 0xAAAAAAAA;
然后在第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;
}                    
A = 0xBBBBBBBB;
B = 0xAAAAAAAA;
现在,如果要取消对
A
B
的引用,您将得到以下结果(注意,您必须首先转换为可取消引用的指针类型):

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

请记住,有两种截然不同的价值观在起作用。首先是指针的值。第二个是指针的地址


您需要使用
extern
的唯一原因是使用在另一个对象文件中定义的变量(即在
file1.c
中,您希望使用在
file2.c
中定义的全局变量)。当应用于全局变量时,
static
关键字表示该变量是文件静态变量,或者只能在该文件中使用。因此,这两个问题显然存在分歧。

我想知道您为什么需要这个?这是一个简化的示例。在我的嵌入式应用程序中,该技术初始化20x4 LCD显示屏上显示的菜单链接列表。每个菜单都有指向相邻菜单的指针,用于导航。作为一个非问答的旁白,将菜单存储在数组中并通过索引而不是指针链接是否更简单?听起来splint不理解暂定定义。我建议您向开发人员提交一份bug报告。
extern
将为其提供外部链接,而不是内部链接。这不是一个重新声明,它实际上是一个所谓的试探性定义,它是一个完美的克隆C。
extern
可能有助于实现什么?代码是完全有效的。@AndreyT:我不知道OP真正想要实现什么,所以我建议指向某个实际的容器。“extern”关键字没有帮助,我将修正答案。K&R2(A10.2)仅为外部对象定义暂定定义,而不是静态定义。然而,较新的ISO规范支持这个答案,特别允许对静态变量进行暂定定义。@a b:我肯定不是这样的。在这种情况下,您误解了“外部”一词的含义。“外部”不代表外部链接。原始ANSI C89/90的“6.7.2外部对象定义”标题中的“外部”一词(我敢肯定,在K&R2中)指的是在文件范围内的函数之外的定义。在这种情况下,“外部”只是指非本地。C89/90中的6.7.2明确允许使用
static
声明对象的暂定定义。尽管K&R2于1988年发布,但它与C89/90是同步的,所以它应该说明同样的事情。