【问题标题】:warning in extern declaration外部声明中的警告
【发布时间】:2010-11-24 15:42:17
【问题描述】:
#include<stdio.h>
#include<stdlib.h>
#define GREY 1
#define BLACK 0
#define WHITE 2
typedef struct node * graph;
typedef struct stack * snode;

graph cnode(int data);          //cnode is to create a node for graph
void cgraph(void);
struct node {
        int data, color;
        struct node *LEFT, *RIGHT, *TOP, *DOWN;
};//this structure defines a node of the graph

struct stack {
struct stack *priv;
struct cgraph *graph_node;
};// this is to define a structure which should hold node of a structure

    extern snode sroot;

我在上面定义了一个头文件(declaration.h),下面是一个c程序(stack.c) 我正在制作的将在我正在开发的库中使用

#include<declarations.h>
void cstack (graph temp);
void stackpush(snode stemp);
extern int stack_counter = 0;

sroot=NULL;
void cstack (graph gtemp) //cstack is to create stack
{
   snode spriv,some;
  if (stack_counter==0)
  {
   sroot=stackpush(gtemp);
    spriv=sroot;
   stack_counter++;
   }
   else{
   some=cstacknode(gtemp);
    some->priv=spriv;
    spriv=some;
  }

}

//struct stack is representing a stack
//struct node is representing a node in graph

snode  cstacknode (graph gtemp)
//this function should create a node of the stack which should be storing the graph node as a pointer
{
 snode an;
 an=(snode)malloc(sizeof(snode));
 an->graph_node=gtemp;
 an->priv=NULL;
 return an;
}

void stackpush(snode stemp)
{

}

以上两个文件都在同一个目录中。 我编译了上面的文件stack.c cc -I ./ stack.c我遵循警告

stack.c:4: warning: ‘stack_counter’ initialized and declared ‘extern’
stack.c:6: warning: data definition has no type or storage class
stack.c:6: error: conflicting types for ‘sroot’
./declarations.h:21: note: previous declaration of ‘sroot’ was here
stack.c:6: warning: initialization makes integer from pointer without a cast
stack.c: In function ‘cstack’:
stack.c:12: warning: passing argument 1 of ‘stackpush’ from incompatible pointer type
stack.c:3: note: expected ‘snode’ but argument is of type ‘graph’
stack.c:12: error: void value not ignored as it ought to be
stack.c:13: warning: assignment makes pointer from integer without a cast
stack.c:17: warning: assignment makes pointer from integer without a cast
stack.c: At top level:
stack.c:27: error: conflicting types for ‘cstacknode’
stack.c:17: note: previous implicit declaration of ‘cstacknode’ was here
stack.c: In function ‘cstacknode’:
stack.c:32: warning: assignment from incompatible pointer type

我想知道我何时将一个变量声明为 extern,我已将其标记为粗体,为什么我会将此作为警告,对此有任何想法,如果有人想就剩余错误分享任何其他内容,请告诉我。

【问题讨论】:

  • 我相信 nmichaels 的答案(在撰写本文时排在第二位)是正确答案:在头文件中声明您的 extern 并在您的 c 文件中定义它而不使用 extern。如果其他文件想要使用这个变量,他们将必须包含头文件并与 c 文件链接。这样,您还可以在一个地方声明类型,并且编译器可以检查不匹配(我不确定链接器是否会注意到两个文件是否以不同方式声明了相同的 extern)。

标签: c


【解决方案1】:

虽然您的代码包含许多相当严重且明显的错误(已在其他答案中涵盖),但您在问题标题中提出的警告是完全多余的无意义警告。 GCC 编译器因发出无用的警告而臭名昭著。其中许多警告似乎源于某人无能且完全没有根据的信念,即做某事在某种程度上是“错误的”,而实际上并没有错。

在您的情况下,警告是由

触发的
extern int stack_counter = 0;

声明。显然,警告的“作者”认为 extern 说明符应该保留给非定义声明。在这种情况下,初始化器= 0 的存在将声明转换为定义(因此正式使extern 成为可选)。尽管如此,它并没有错误,事实上,extern 在这里可能会很受欢迎,以强调 stack_counter 旨在成为一个全局变量这一事实。

同样,您是否需要一个全局变量是一个不同的问题,同样,您的代码包含大量其他错误。但是,您似乎将注意力集中在的警告并不值得。只需在编译器设置中禁用此警告(并请向 GCC 团队写一封粗鲁的信)。

【讨论】:

  • 公平地说,这是一个可以预示(并帮助解决)链接器错误(多重定义)的警告。例如...在 TU 1 中创建一个全局并分配它,然后在 TU 2 中我们复制声明,然后将 extern 添加到该声明之前。与 extern 一起存在的初始化使 extern 意味着不同的东西,从而导致创建此变量的两个实例和链接器 barfs... 这并不是说您的观点不那么有效,但这可能是原因存在的警告......
  • @StevenLu:所以,GCC 在错误发生之前发出警告,然后错误发生在链接阶段。很棒的东西。
  • 好吧,像 if (x=1) { ...} 这样的代码是完全合法的,但通常欢迎使用警告。
  • @alecov 这就是为什么你应该总是使用-Werror。 GCC 在编译你的无效代码方面非常棒,但最好是防止编译不正确的代码。
  • 预期用途是在一个文件中有一个外部定义,例如int a; 和一个或多个 声明 extern int a; 在其他文件中。然后使用extern 可以表明该变量在其他位置定义(可能在同一个文件中,但很可能在不同的源文件中)。 extern int a = 5 违反了这个成语。
【解决方案2】:

头文件中的 extern 声明允许定义变量的模块以外的模块使用它。如果它应该被定义为 int stack_counter = 0 并存在于 stack.c 中,那么就这样定义它并在标题中放置一个 extern stack_counter

在 stack.c 的第 6 行,您没有为 sroot 定义存储类。由于它在标题中,我假设您的意思是输入snode sroot=NULL

修复这些问题,然后实施 stackpush(确保它不返回 void)并按顺序处理其余的警告。请注意,在 C 中,您必须使用函数的前向声明(带有原型)或在使用函数之前定义函数。 cstack 函数应该是文件中的最后一个函数。

【讨论】:

  • 哦,好的,感谢您指出这些错误修改后的事情让我知道我想进一步讨论这个问题,因为我如何将 c 程序放在我的回复中,以便代码在 stackoverflow 上可读。我尝试添加反引号 ` 和 ' 但没有奏效。
  • @Bond:无法在 cmets 中完成。您最好的选择是更新问题以反映更改。或者,如果您所做的更改让您陷入了困境,请提出一个新问题。
【解决方案3】:

我刚刚收到了 gcc 的警告,这是一个简单的修复。 stack_counter 不应在标头中初始化,而应在包含它的源文件中初始化。所以标题应该只使用:

extern int stack_counter;

然后在仅包含该标头的一个源文件的全局范围内声明并初始化 stack_counter:

int stack_counter = 0;

【讨论】:

    【解决方案4】:

    Clang 仍然会为此发出警告。线

    extern int counter = 0;
    

    会触发警告:

    警告:'extern' 变量有一个初始化器 [-Wextern-initializer]

    这个警告并不重要,因为定义变量用

    int counter = 0;
    

    默认情况下仍会产生静态持续时间和外部链接。实际上,如果没有提供存储类说明符,则默认值为:

    • extern 用于所有功能
    • extern 用于文件范围内的对象
    • auto 用于块范围内的对象

    还有一种叫做暂定定义的东西,它是一个没有初始化器的外部声明,或者没有存储类说明符或带有说明符static

    暂定定义是一个声明,它可以作为定义,也可以不作为定义。如果在同一个翻译单元中更早或更晚地找到了实际的外部定义,则暂定定义仅充当声明。

    所以下面一行

    int counter;
    

    是一个暂定定义,它使用隐式初始化器= 0(或者,对于数组、结构和联合类型,= {0})声明和定义counter

    【讨论】:

      猜你喜欢
      • 2013-02-21
      • 2021-09-08
      • 2011-02-21
      • 1970-01-01
      • 1970-01-01
      • 2015-08-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多