2014-01-16 33 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之一,並在整個程序中使用它。

相關問題