Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Warning: implicit declaration of function — why does my code work anyway?

I have gone through the following threads:

  • warning: implicit declaration of function
  • Implicit Declaration of Function in C UNIX

Possibly my issue is linked. But while they offer the solution that the function prototype should be declared before the function is used, I wanted to explore what happens when the function name is not matching. In my test, it still works fine.

Main C file

#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 file

#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 file

#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");
    }
}

Output

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

The name of the function declared in the node.h is insert_node whereas in node.c it is create_node. Can someone share some insight on why is it running? It throws a warning though:

Warning: implicit declaration of function

like image 903
Vikas Goel Avatar asked Dec 26 '22 15:12

Vikas Goel


2 Answers

First, you've declared a function called insert_node, but that doesn't matter. It's ok to declare functions, but not define them (i.e. not provide their code), as long as you don't use the function. This happens often in real life: headers define a lot of functions, and then at link time only the functions that are actually used need to be provided.

The warning concerns create_node. Since there is no declaration of the function when you compile the main C file, the compiler makes some assumptions about its parameter types. It promotes all arguments: integer types smaller than int (e.g. char and short) are promoted to int; floats are promoted to double; pointer types are not converted. With your code, this happens to work because

  • you're always passing arguments of the right type;
  • none of the argument types are promoted.

If you changed the type of the data parameter to long, then the compiler would generate code to call the function assuming an int type but the function would expect a long argument. On a platform where int and long have different sizes, you might get garbage data, a crash, or other misbehavior.

If you changed the type of the data parameter to char, then the compiler would generate code to call the function assuming an int type but the function would expect a char argument. Again, you might find that the code uses wrong data, crashes, etc.

C generally gives you enough rope to hang yourself. If you cut a piece of rope in the wrong way, it might just happen to work. Or it might not.

like image 112
Gilles 'SO- stop being evil' Avatar answered May 16 '23 08:05

Gilles 'SO- stop being evil'


In your example, you have an implicit declaration of create_node and declare an unimplemented function insert_node.

Calls to create_node work for reasons that'll be covered in the previous posts you link to.

The fact that insert_node isn't implemented doesn't matter for your program because nothing tries to call it. If you changed a line to call insert_node, it would compile without warning but then fail to link with an unresolved symbol error for insert_node.

I'm sure you know this, but the correct approach here is to standardise on one of create_node or insert_node and use that throughout your program.

like image 26
simonc Avatar answered May 16 '23 07:05

simonc