2014-01-16 17 views
3

我已经通过以下线程不见了:警告:函数的隐式声明 - 为什么我的代码无论如何工作?

可能我的问题是联系在一起的。但是,尽管他们提供了在使用函数之前应该声明函数原型的解决方案,但是我想探索当函数名称不匹配时会发生什么。在我的测试中,它仍然正常工作。

主C文件

#include "node.h" 
int main(){ 
    nd *head=NULL; 
    nd *tail=NULL; 

    create_node(&head, &tail, 10); 
    create_node(&head, &tail, 20); 
    create_node(&head, &tail, 15); 
    create_node(&head, &tail, 35); 
    create_node(&head, &tail, 5); 
    create_node(&head, &tail, 25); 
    print_list(head, tail); 
    create_node(&head, &tail, 55); 
    create_node(&head, &tail, 52); 
    create_node(&head, &tail, 125); 

    printf("%d\n",tail->data); 
    printf("%d\n",head->data); 
    print_list(head, tail); 
    return 0; 
} 

node.h文件

#ifndef NODE_H 
#define NODE_H 

#include<stdio.h> 
#include<stdlib.h> 

typedef struct node{ 
    int data; 
    struct node *next; 
    struct node *prev; 
}nd; 

void insert_node(nd **head, nd **tail, int data); 

void print_list(nd *head, nd *tail); 

#endif 

node.c文件

#include "node.h" 
void create_node(nd **head, nd **tail, int d){ 

    nd *temp=(nd *) malloc(sizeof(nd)); 
    temp->data=d; 
    temp->next=NULL; 
    temp->prev=NULL; 
    /* Start of the Queue.    */ 
    if(*head==NULL && *tail==NULL){ 
     *head=temp; 
     *tail=temp; 
    } 
    /* Linking with tail of the Queue.    */ 
    else if((*tail)->next==NULL){ 
     (*tail)->next=temp; 
     temp->prev=*tail; 
     *head=temp; 
    } 
    /* Adding remaining elements of the Queue.  */ 
    else{ 
     (*head)->next=temp; 
     temp->prev=*head; 
     *head=temp; 
    } 
} 

void print_list(nd *head, nd *tail){ 
    if(NULL==head){ 
     printf("Queue is empty\n"); 
    } 
    else{ 
     printf("Printing the list\n"); 
     nd *temp; 
     for(temp=tail;temp!=NULL;temp=temp->next){ 
      printf("%d ",temp->data); 
     } 
     printf("\n"); 
    } 
} 

输出

Printing the list 
10 20 15 35 5 25 
10 
125 
Printing the list 
10 20 15 35 5 25 55 52 125 

node.h声明的函数的名称是insert_node而在node.c是create_node。有人可以分享一些有关它为什么运行的见解吗?它虽然抛出一个警告:

Warning: implicit declaration of function

+1

它的工作原理是'main'调用'create_node','create_node'是'node.c'中实际声明的内容。参数类型恰好足够通用,它们都可以。标题中名称中的错误会导致警告。如果'node.c'中的'create_node'实际上被称为'insert_node',则链接将失败并且说它找不到定义为'create_node'的函数。 – lurker

+2

是你的问题“为什么我的编译器不会将警告视为错误?”这是一个标志。 – geoffspear

+1

这不是“正常工作”。如果调用未声明的函数产生一些输出,那么它是错误的,无论如何(因为行为是未定义的)。虽然它可以*假装*以“工作正常”。这并不意味着它确实可以正常工作。 – 2014-01-16 18:13:41

回答

4

首先,您声明了一个名为insert_node的函数,但这并不重要。声明函数是可以的,但不定义它们(即不提供它们的代码),只要你不使用该函数即可。这经常发生在现实生活中:标题定义了很多功能,然后在链接时只需要提供实际使用的功能。

警告涉及create_node。由于编译主C文件时没有声明该函数,因此编译器会对其参数类型进行一些假设。它促进了所有参数:小于int(例如charshort)的整数类型被提升为int; float s被提升为double;指针类型不转换。随着你的代码,这发生工作,因为

  • 你总是通过正确的类型的参数;
  • 没有任何参数类型被提升。

如果更改了data参数的类型long,那么编译器将生成代码来调用该函数假定一个int类型但功能会期望一个long说法。在intlong具有不同大小的平台上,您可能会收到垃圾数据,崩溃或其他不当行为。

如果更改了data参数的类型char,那么编译器将生成代码来调用该函数假定一个int类型但功能会期望一个char说法。再次,您可能会发现代码使用错误的数据,崩溃等。

C通常会给您足够的绳子来吊死自己。如果你以错误的方式切断了一条绳索,它可能恰好正常工作。或者它可能不会。

+1

可能值得一提的是,这里所描述的所有内容在C89中都是真实的。 C99将未声明的函数调用为无效。 – 2014-01-16 22:18:59

+0

@ H2CO3好点,但由于代码无效且编译器发出诊断信息,C89编译器可以保持完全相同的行为,并且符合C99的要求。 – Gilles

+0

对不起,我不明白。这在C89和C99下不可能表现得相同。在C89中,如果升级的参数类型匹配,则它是*必需的*,而在C99中则是UB。 (我也没有看到“C89编译器符合C99”的意思,这也是不可能的,请您详细说明一下吗?) – 2014-01-16 22:25:54

4

在你的榜样,你有create_node一个隐含的声明,声明中未实现的功能insert_node

致电create_node的工作原因将在您链接到的以前的帖子中涵盖。

insert_node未实现的事实对您的程序无关紧要,因为没有任何设法调用它。如果您更改了一行来呼叫insert_node,它会在没有警告的情况下进行编译,但无法链接到insert_node的未解决符号错误。

我相信你知道这一点,但这里的正确方法是标准化create_nodeinsert_node之一,并在整个程序中使用它。

相关问题