函数声明和定义的一致性

问题描述 投票:0回答:3

有消息来源告诉我:

定义函数的源文件应包含包含该函数的标头 函数的声明。这样编译器将验证定义和 声明一致。

我不确定这是如何正确的,我们在谈论什么类型的“一致性”?因为如果定义和声明在返回类型或参数类型/数字方面不一致,编译器只会认为我正在声明一个单独的函数,并且根本不会验证任何内容。

例如如果我有一个头文件 test.h:

 void func();

还有一个源文件testsource.cpp:

 #include <iostream>
 #include "test.h"
 using namespace std;

 void func(int x){
     cout << "Hello StackOverflow" << endl;
 }

如果我运行这个程序,编译器只会认为 func() 和 func(int) 是不同的函数,并且不会对一致性大惊小怪。它指的是哪种类型的一致性?

c++ declaration consistency
3个回答
3
投票

一个有趣的问题。你的“来源”[我认为是一个人或一本书,或者......]是错误的。尽管在头文件中使用与包含函数体的文件具有相同基本名称的函数声明是一种常见约定,但并不要求这样做。

当然,除了良好的编码标准。

你是对的,两个具有相同名称但不同参数的函数是完全可以接受的——就像声明一个函数但从不定义它一样(只要你从不调用它)。

C++ 编译器并不能阻止你搬起石头砸自己的脚,但良好的编码实践却可以。

现在您已将书中的引用编辑到问题中,我可以指出该引用说的是“应该”而不是“必须”。常识性用法既不是语言强制的,也不是强制的。这只是很好的编程实践。

另请注意,lint 类型的程序很可能会检测并抱怨这一点,即使编译器不会。


1
投票

如果您有另一个依赖于您的

func
的编译单元,例如,这样定义的
bar.cpp

#include "test.h"

void bar()
{
    func();
}

此编译单元导入您的标头,编译器将假设存在另一个目标文件,该文件定义了该

test.h
标头中声明的内容。

现在,如果您只让

testsource.cpp
定义了不同的函数(具有不同函数签名的函数),则此阶段的编译器将报告链接错误:
func()
中引用的符号
bar.cpp
不能在其链接输入中的任何位置都可以找到!


0
投票

因为如果定义和声明在返回类型或参数类型/数字方面不一致,编译器就会认为我正在声明一个单独的函数......

这是真的。从某种意义上说,编译器只会认为这一点,从某种意义上说,您很可能正在声明(并定义)一个单独的函数。就语言而言完全有效。

...并且根本不会验证任何事情。

这并不完全正确。编译器仍然可以验证一些东西。虽然它不能抱怨(在您的示例中)

func(int)
定义与
func()
声明不匹配,但它可以抱怨/警告
func(int)
定义与any声明不匹配。

目标是发现可能是错误的不匹配。通常,如果遵循良好实践,具有外部链接的非

inline
函数应在定义(在源文件中)之前声明(在标头中)。如果不是,那么就有理由认为程序员犯了错误。如果发生这种情况,可能会要求某些编译器发出警告。

(因为这个问题很旧,所以我做了一些挖掘。虽然我不知道这个选项是什么时候添加的,但它在 gcc 4.4.7 中可用,该版本于 2012 年 3 月 13 日发布,比这个问题早三年所以这无论是现在还是提问时都是有效的答案。)

海湾合作委员会

对于 gcc,选项是

-Wmissing-declarations
(不包含在
-Wall -Wextra
中,可能是因为设置没有错误,只是可能是无意的):

如果在没有事先声明的情况下定义了全局函数,则会发出警告。即使定义本身提供了原型,也要这样做。使用此选项可以检测未在头文件中声明的全局函数。在 C 中,对于先前具有非原型声明的函数不会发出警告;使用

-Wmissing-prototypes
检测缺失的原型。在 C++ 中,不会针对函数模板、内联函数或匿名命名空间中的函数发出警告。

在启用此警告的情况下编译示例代码会给出

警告:之前没有声明“void func(int)”[-Wmissing-declarations]

所以您知道要仔细检查您的声明。

© www.soinside.com 2019 - 2024. All rights reserved.