【问题标题】:C warning: implicit declaration of functionC 警告:函数的隐式声明
【发布时间】:2010-11-16 01:50:09
【问题描述】:

是的,这个问题已经被问过很多次了,我一直在寻找和阅读论坛和 SO 帖子,但答案都与这个问题无关(或者看起来如此)。所以,我有这个 main 文件:

-- sgbd_server.c --

#include "sgbd_server.h"

/**
 * Open server pipe and return handle. -1 = error
 */
int open_server_pipe() {
    return pipe_open(FIFO_NAME, O_RDONLY, S_CON_COLOR);
}

/**
 * Close server pipe
 */
void close_server_pipe(int fd) {
    pipe_close(fd, FIFO_NAME, S_CON_COLOR);
}


int main(int argc, char *argv[]) {
    int pipe_fd;
    pipe_fd = open_server_pipe();

    if (pipe_fd == -1) {
        perror("Cannot open pipe");
    }

    close_server_pipe(pipe_fd); 

    exit(EXIT_SUCCESS);
}

然后是头文件:

-- sgbd_server.h --

#include "common.h"

#define FIFO_NAME "./sgbd_server_pipe"
#define BUFFER_SIZE PIPE_BUF

#define S_CON_COLOR 1   /* C_COLOR_RED */

-- common.h --

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>

#include "console.h"

#define CLIENT_FIFO_PREFIX = "./sgbd_client_"

int pipe_open(char *f, int mode, int color);

void pipe_close(int pipe_fd, char *f, int color);

pipe_openpipe_close 两个函数在pipe.c 中定义,基本上返回0void。最后一个文件在 Make 文件中单独编译。

我不是制作 Make 文件的专家,但为了这个问题,这里是:

SERVER    = sgbd_server
CLIENT    = sgbd_client

CC        = gcc
C_FLAGS   = -Wall -I.
LINKER    = gcc
L_FLAGS   = -Wall -l pthread -Wall -I.

RM        = rm -f


client: sgbd_client.o pipe.o console.o
    @echo -n "Building client... "
    @$(LINKER) $(L_FLAGS) -o $(CLIENT) sgbd_client.o pipe.o console.o
    @echo "Complete!\n"

server: sgbd_server.o pipe.o console.o
    @echo -n "Building server... "
    @$(LINKER) $(L_FLAGS) -o $(SERVER) sgbd_server.o pipe.o console.o
    @echo "Complete!\n"

sgbd_client.o: sgbd_client.c
    @echo -n "Refreshing client sources... "
    @$(CC) $(C_FLAGS) -c sgbd_client.c
    @echo "Done!"

sgbd_server.o: sgbd_server.c common.h
    @echo -n "Refreshing server sources..."
    @$(CC) $(C_FLAGS) -c sgbd_server.c common.h
    @echo "Done!"

pipe.o: pipe.c
    @echo -n "Refreshing pipe sources..."
    @$(CC) $(C_FLAGS) -c pipe.c
    @echo "Done!"

console.o: console.c
    @echo -n "Refreshing console sources..."
    @$(CC) $(C_FLAGS) -c console.c
    @echo "Done!"

clean:
    @echo -n "Cleaning up executables and object files... "
    @$(RM) $(SERVER) $(CLIENT) *.o
    @echo "Ok\n"

** 注意 ** : 文件console.c 并实现了一些功能来控制控制台上的I/O,没什么花哨的。如您所见,它也是单独编译的。

现在,当我输入make client 时,一切都很好,鸟儿正在签名等等。但是当我输入make server 时,它会吐出来

sgbd_server.c: In function ‘open_server_pipe’:
sgbd_server.c:7: warning: implicit declaration of function ‘pipe_open’
sgbd_server.c: In function ‘close_server_pipe’:
sgbd_server.c:14: warning: implicit declaration of function ‘pipe_close’

如果有什么不同,我会在 Linux amd64 上运行 GCC(我对此表示怀疑)。

现在,它为什么要警告我呢?这两个函数在common.h 中声明,它包含在sgbd_server.h 中......我在这里缺少什么?

感谢您的宝贵时间!

** 更新 **

谢谢大家的建议。我确实尝试查找在我的包含路径中的其他地方是否会有一个文件common.h 会以某种方式被包含...虽然我没有找到任何会在编译过程中滑倒而不是本地common.h 的文件( sig) 我在我的源文件夹中发现了一些 .ghc 文件。由于make clean 没有清理它们,我手动删除了这些文件。你猜怎么了?没有警告。这些文件是什么?为什么要创建它们?

【问题讨论】:

  • 对 sgbd_server.c 中的#inclde "common.h" 有帮助吗?
  • 我看不出有任何理由。 sgbd_client.c 长什么样子?
  • 尝试使用gcc -E sgbd_server.c 来查看预处理器完成后编译的确切内容。
  • @vpit3833,它没有。实际上,如果我这样做,它会抱怨我的结构 Info_FIFO_Transaction 被重新定义。
  • @caf,我不太确定如何处理所有转储... :) 在这里:paste2.org/p/1092385

标签: c warnings gcc-warning


【解决方案1】:

首先,我认为在 makefile 中将common.h 提供给编译器并不是一个好主意:

@$(CC) $(C_FLAGS) -c sgbd_server.c common.h

这样会更好:

@$(CC) $(C_FLAGS) -c sgbd_server.c

头文件通常只包含#include。您似乎在告诉编译器尝试将 common.h 编译为独立的 C 文件。这是客户端和服务器编译命令之间的一个区别,您应该修复它。

我唯一可以建议的另一件事是,您可能没有获得您认为您正在获得的头文件。先放一行:

#error Urk! in common.h

在您的 common.h 顶部并确保构建失败。

如果不是,那么该文件来自其他地方。您可能还想对您的 sgbd_server.h 文件执行相同的操作。


根据您的编辑:

我在我的源文件夹中发现了一些 .ghc 文件。由于 make clean 没有清理它们,因此我手动删除了这些文件。你猜怎么了?没有警告。这些文件是什么?为什么要创建它们?

这些是,假设ghc 是一个错字,你的意思是gch,由gcc 生成的预编译头文件,至少部分是为了加快编译过程。无需在构建期间多次处理头文件(每个包含它的源文件一次),预编译一次并使用预编译版本效率更高。

我认为这很可能是因为您在编译服务器时在编译器命令行中包含了common.h。默认情况下,直接提供给gcc 的头文件将被转换为预编译的头文件,并在此之后优先使用。为了测试这一点,我创建了一个qq.h 文件并执行gcc qq.h 并弹出qq.h.gch

很有可能,删除它们解决了您的问题,这些文件以某种方式导致了您的问题(可能是存在比实际头文件更旧的预编译头文件或完全其他问题)。您的编译行很有可能:

@$(CC) $(C_FLAGS) -c sgbd_server.c common.h

将首先编译服务器程序,包括旧的预编译头文件,然后从较新的头文件中制作一个新的预编译头文件。

这可能就是为什么对common.h 的更改没有(立即)效果。您必须make ; touch common.h ; make 以确保在服务器程序中使用较新的预编译头文件。

你是否想追根溯源并得到一个正确的解释是个人喜好问题 - 有一种观点认为你有时应该记录你是如何解决它的,不要太担心,以免你被纠缠在现实本身的本质中。

当然不是我,我是那种会试图将我的问题追溯到造成问题的单个亚原子粒子的性格类型,但有时实用主义要求我放手 :-)

【讨论】:

  • 我删除了 makefile 中对 common.h 的所有引用(当警告开始出现时它们最初并不存在)。但是,#error 指令并没有改变任何东西,这意味着编译器似乎根本没有直接在源代码中直接包含common.h 文件!
  • 当我将#include "common.h" 直接放入sgbd_server.c 时,警告消失了,但我收到了error: redefinition of ‘struct Info_FIFO_Transaction’ 消息。 O_o
  • 可以使用响应者一直在谈论的条件保护来删除重定义错误。
  • @Yanick,如果您的文件中有 #include "common.h" 并且您认为正在使用的文件中有 #error 指令不会中止编译,那么我的论点是您是使用你认为的那个。您可以尝试使用 gcc -E 并捕获输出 - 这可能会告诉您包含文件的来源(刚刚测试过,此处的输出包括每个包含文件的 完整 路径名)。
  • 问题已解决。我也喜欢追查问题,找出“为什么”,但可能不是亚原子级别:) 我对 A->B->C 很好,删除 B 然后你会得到 A->C解决方案的类型。
【解决方案2】:

观察:你在#define 中有一个 =,我怀疑你不是故意的

#define CLIENT_FIFO_PREFIX = "./sgbd_client_"

应该是

#define CLIENT_FIFO_PREFIX "./sgbd_client_"

cmets:当原型包含形式参数名称(除了强制类型)并且函数的定义使用不同的形式参数名称时,我偶尔会看到编译器的奇怪行为。 IE。在你的pipes.c 你是pipes.c吗 包括 common.h?

另外,条件保护 #ifndef headerfilename #define headerfilename #endif 是一个很好的做法,但这与您的问题没有直接关系。

.PMCD.

【讨论】:

    【解决方案3】:

    我怀疑您可能包含另一个名为 common.h 的文件,而不是您期望的文件。我复制并粘贴了你的文件,它编译时没有任何警告。

    【讨论】:

    • 当前工作中没有其他 common.h 直接在所有文件所在的位置......除非有一个我不知道的common.h......
    • /usr/include 或其他默认包含目录中可能存在某些内容。试试 paxdiablo 建议的 #error 指令。这将证明它是否从本地目录获取文件。
    • 当我将common.h 包含在sgbd_server.c 中时,它似乎包含了所有的写,但是当它包含在sgbd_server.h 中时,它就不包含了……这很奇怪。尽管如此,我重命名了common.h,但同样的行为仍然存在。
    【解决方案4】:

    您发布的文件中的包含看起来应该可以工作。一些想法还有什么可能是错误的:

    • common.hconsole.h 是否会尝试包含 sgbd_server.h,从而最终得到循环包含?
    • 您是否使用了包含保护(甚至是其他 #ifdefs)并且可能将它们混合在某个地方,从而无意中排除了其中一个文件?
    • 您是否在某处有另一个 common.h 包含路径,可能会被包含,而不是您想要的路径?

    【讨论】:

    • 不。这就是我在这里问的原因,这正是所有被编译的文件……到目前为止,您已经获得了所有源代码(从今天开始);您所看到的就是正在编译的内容。
    猜你喜欢
    • 2012-12-13
    • 1970-01-01
    • 1970-01-01
    • 2012-01-16
    • 1970-01-01
    相关资源
    最近更新 更多