C 警告:函数的隐式声明— ;我的代码为什么还能工作?
我经历了以下几个方面:C 警告:函数的隐式声明— ;我的代码为什么还能工作?,c,function,warnings,implicit-declaration,C,Function,Warnings,Implicit Declaration,我经历了以下几个方面: 我的问题可能与此有关。但是,虽然它们提供了在使用函数之前应该声明函数原型的解决方案,但我想探究当函数名不匹配时会发生什么。在我的测试中,它仍然可以正常工作 主C文件 #include "node.h" int main(){ nd *head=NULL; nd *tail=NULL; create_node(&head, &tail, 10); create_node(&head, &tail, 2
#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;
}
#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
#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");
}
}
node.h
文件
#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;
}
#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
#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\u node
,而在node.c中声明的函数名是create\u node
。有人能分享一些关于它为什么运行的见解吗?但它发出了一个警告:
警告:函数的隐式声明
在您的示例中,您有一个隐式声明
create\u node
,并声明一个未实现的函数insert\u node
调用create_node
的原因将在您之前链接到的帖子中介绍
没有实现insert\u node
这一事实对您的程序来说并不重要,因为没有任何东西试图调用它。如果将一行更改为调用insert\u node
,它将在没有警告的情况下编译,但随后无法链接到insert\u node
的未解决符号错误
我相信您知道这一点,但正确的方法是在
创建\u节点
或插入\u节点
之一上进行标准化,并在整个程序中使用它。首先,您声明了一个名为插入\u节点
的函数,但这并不重要。只要不使用函数,就可以声明函数,但不定义它们(即不提供它们的代码)。这在现实生活中经常发生:头定义了很多函数,然后在链接时只需要提供实际使用的函数
警告与创建节点有关。由于编译主C文件时没有函数声明,编译器会对其参数类型进行一些假设。它提升所有参数:小于int
(例如char
和short
)的整数类型提升为int
float
s被提升为double
;指针类型不转换。对于您的代码,这恰好起作用,因为
- 您总是传递正确类型的参数李>
- 所有参数类型均未升级
数据
参数的类型更改为long
,则编译器将生成代码以调用函数,并假定函数的类型为int
,但该函数将使用long
参数。在int
和long
大小不同的平台上,您可能会得到垃圾数据、崩溃或其他错误行为
如果将数据
参数的类型更改为字符
,则编译器将生成代码来调用函数,并假定函数的类型为int
,但该函数需要一个字符
参数。同样,您可能会发现代码使用了错误的数据、崩溃等
C通常会给你足够的绳子吊死自己。如果你把一根绳子剪错了,它可能正好起作用。或者它可能不起作用。它起作用是因为
main
调用create\u node
,而create\u node
实际上是在node.c
中声明的。参数类型恰好足够通用,因此它们都是OK的。标题中的名称错误将导致警告。如果node.c
中的create\u节点
实际上被称为insert\u节点
,该链接将失败,并说它找不到定义为create\u节点
的函数。您的问题是“为什么我的编译器不将警告视为错误?”这是一个标志。它不是“工作正常”。如果调用未声明的函数会产生一些输出,那么不管发生什么,这都是错误的(因为行为当时是未定义的)。不过,它可以假装“工作正常”。这并不意味着它确实工作正常。如果使用gcc@H2CO3接受的答案解释了在这种情况下,带参数的默认编译器行为是可以的。虽然隐式声明可能并不总是正确的,但在这种情况下,它看起来不仅仅是“假装工作正常”;编译器所做的假设在这种情况下是正确的,因此这种情况是正确的。值得一提的是,您在这里描述的所有内容仅在C89中是正确的。C99使对未声明函数的调用无效。@H2CO3这一点很好,但由于代码无效且编译器已发出诊断,C89编译器可以保持完全相同的行为方式,并在这一点上符合C99。抱歉,我不理解。这在C89和C99下不可能有相同的行为。在C89中,如果提升的参数类型匹配,则它必须工作,而在C99中它是UB。(我也不明白你所说的“C89编译器将遵守C99”是什么意思,这也是不可能的。你能详细说明一下吗?@H2CO3有了C89编译器,这个例子必须工作——但问题是这个例子如何工作。对于C99,这个示例不必工作,但仍然允许编译器使其工作。