C编程中前向声明的意义是什么?
What is the significance of forward declaration in C programming?
我现在正在通过 Zed A. Shaw 的 Learn C the Hard Way 学习 C 编程。有这段代码(取自他的网站):
#include <stdio.h>
#include <ctype.h>
// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);
void print_arguments(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++) {
print_letters(argv[i]);
}
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '[=10=]'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
int main(int argc, char *argv[])
{
print_arguments(argc, argv);
return 0;
}
难道我们不能像这样编码吗(将 can_print_it
和 print_letters
函数放在顶部并删除前向声明的需要):
#include <stdio.h>
#include <ctype.h>
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '[=11=]'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
真的有前向声明重要且不可避免的时候吗?
当你的调用图是循环的时候,函数的前向声明是不可避免的;也就是说,只要您在函数之间进行(直接或间接)递归。
如果您想将程序分成多个翻译单元,它们很有用,因为它们允许分离函数的声明和定义(将声明放在 .h
header 和 .c
文件中的定义)。
前向声明取决于程序的需要。程序员可以自己设计。
Understand the significance: In C and C++, the line above represents a
forward declaration of a function and is the function's prototype.
After processing this declaration, the compiler would allow the
program code to refer to the entity printThisInteger in the rest of
the program. The definition for a function must be provided somewhere
(same file or other, where it would be the responsibility of the
linker to correctly match references to a particular function in one
or several object files with the definition, which must be unique, in
another):
您应该按照合理的顺序声明函数。这应该在您遵循的编码风格文档中进行描述。常见设计的一个例子是:
- 包含所有 publically 可用函数声明的 h 文件。
- c 文件,所有私有函数声明都在顶部。
- 然后在同一个 c 文件中遵循 public 函数的函数定义。
- 然后在该 c 文件的末尾,私有函数的函数定义。
除了样式和设计方面的问题,如果在函数调用之前根本看不到原型,C 的古代版本将开始 "make up" 函数参数和 return 类型。
C 中函数的前向声明通常有两种不同的用途。
模块
导出函数的头文件在包含在客户端模块中的头文件中声明。
相互递归
在相互递归中,两个函数重复调用对方。如果没有前向声明,两个函数中的一个将在另一个函数的主体中未声明。
示例:
int Odd(int n);
int Even(int n)
{
return (n == 0)? 1: Odd(n - 1);
}
int Odd(int n)
{
return (n == 0)? 0: Even(n - 1);
}
不过有了函数指针,我们可以不用前向声明:
int (*odd)(int n);
int Even(int n)
{
return (n == 0)? 1: odd(n - 1);
}
int Odd(int n)
{
return (n == 0)? 0: Even(n - 1);
}
void Init(void)
{
odd = Odd;
...
}
我现在正在通过 Zed A. Shaw 的 Learn C the Hard Way 学习 C 编程。有这段代码(取自他的网站):
#include <stdio.h>
#include <ctype.h>
// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);
void print_arguments(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++) {
print_letters(argv[i]);
}
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '[=10=]'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
int main(int argc, char *argv[])
{
print_arguments(argc, argv);
return 0;
}
难道我们不能像这样编码吗(将 can_print_it
和 print_letters
函数放在顶部并删除前向声明的需要):
#include <stdio.h>
#include <ctype.h>
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '[=11=]'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
真的有前向声明重要且不可避免的时候吗?
当你的调用图是循环的时候,函数的前向声明是不可避免的;也就是说,只要您在函数之间进行(直接或间接)递归。
如果您想将程序分成多个翻译单元,它们很有用,因为它们允许分离函数的声明和定义(将声明放在 .h
header 和 .c
文件中的定义)。
前向声明取决于程序的需要。程序员可以自己设计。
Understand the significance: In C and C++, the line above represents a forward declaration of a function and is the function's prototype. After processing this declaration, the compiler would allow the program code to refer to the entity printThisInteger in the rest of the program. The definition for a function must be provided somewhere (same file or other, where it would be the responsibility of the linker to correctly match references to a particular function in one or several object files with the definition, which must be unique, in another):
您应该按照合理的顺序声明函数。这应该在您遵循的编码风格文档中进行描述。常见设计的一个例子是:
- 包含所有 publically 可用函数声明的 h 文件。
- c 文件,所有私有函数声明都在顶部。
- 然后在同一个 c 文件中遵循 public 函数的函数定义。
- 然后在该 c 文件的末尾,私有函数的函数定义。
除了样式和设计方面的问题,如果在函数调用之前根本看不到原型,C 的古代版本将开始 "make up" 函数参数和 return 类型。
C 中函数的前向声明通常有两种不同的用途。
模块
导出函数的头文件在包含在客户端模块中的头文件中声明。
相互递归
在相互递归中,两个函数重复调用对方。如果没有前向声明,两个函数中的一个将在另一个函数的主体中未声明。
示例:
int Odd(int n);
int Even(int n)
{
return (n == 0)? 1: Odd(n - 1);
}
int Odd(int n)
{
return (n == 0)? 0: Even(n - 1);
}
不过有了函数指针,我们可以不用前向声明:
int (*odd)(int n);
int Even(int n)
{
return (n == 0)? 1: odd(n - 1);
}
int Odd(int n)
{
return (n == 0)? 0: Even(n - 1);
}
void Init(void)
{
odd = Odd;
...
}