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