在使用它之前声明一个函数,它有什么不同吗?
Declaring a function before using it, does it make a difference?
这两个函数体代码有什么区别? (第一段代码来自《The C Programming Language》一书)
声明并使用函数与不先声明就直接使用函数有什么区别?
int atoi(char s[]) {
double atof(char s[]);
return (int) atof(s);
}
int atoi(char s[]) {
return (int) atof(s);
}
第一个源代码示例明确告诉编译器信息,编译器必须在第二个源代码示例中推断。
以下讨论假设函数 atof()
在示例中使用之前未以任何方式(包含文件等)声明或定义。
在第一个示例中,您有一个函数的显式声明 atof()
,它允许编译器执行一些检查以确保它被正确使用。
int atoi(char s[]) {
double atof(char s[]); // atof is a function that takes a character array and returns a double value
return (int) atof(s);
}
顺便说一下,我将其声明为 extern double atof(char s[]);
只是为了让人们清楚 reader 这是一个外部函数。
在第二个示例中,编译器必须推断出 atof()
是一个函数,并且它需要一个 char
数组。编译器使用源代码行和此调用中使用的参数类型来调用未定义和未声明的函数来创建函数声明。
但是编译器不知道函数的 return 值的类型,因为函数的定义不可用,因此为了完成生成的声明,编译器使用默认值 int
.
此编译器生成的声明仅为函数生成。如果使用未定义或未声明的变量,编译器将产生错误。决定它是函数(可能生成声明)还是变量(可能不生成)的关键在于名称后是否有左括号。
int atoi(char s[]) {
return (int) atof(s);
}
带有显式声明的第一个示例为编译器提供了额外的、显式的信息,允许它检查函数的使用。第二个例子,编译器必须做出假设并生成一个声明,然后用它来验证函数是否被正确使用。
这样生成的声明可能导致的一个问题是,如果第一次使用未定义和未声明的函数是不正确的,则编译器生成的声明也是不正确的,并且应该在以下源代码中以不同但正确的方式使用该函数, 编译器可能会生成警告或错误,具体取决于函数的两种用法(一种不正确,一种正确)之间的实际差异。
对于在其他源文件中使用的函数,首选过程是提供一个头文件或包含文件,该文件与包含正在使用的函数的源代码文件一起提供。在此头文件中将声明所有具有外部可见性的函数(换句话说,尚未在源文件中声明 static
)并且此头文件将与包含的目标代码或库文件一起提供编译后的函数定义。
任何使用该函数的人都会包含头文件,以便编译器检查他们是否正确使用了该函数。有一些检查是编译器无法提供或程序员可以解决的,但是有可用的函数声明可以通过编译器的静态语法检查提供基本级别的有效性检查。
一个实验
使用 Visual Studio 2015 进行试验,一旦函数被声明,即使在函数范围内,编译器也会记住该声明并使用该声明检查源文件中的任何其他使用。此外,如果在没有声明的情况下使用该函数,编译器会生成一个声明,然后检查该声明是否存在使用该函数的任何其他地方。
这种记住函数声明的行为与在函数范围内声明外部变量有点不同。外部变量声明仅在其声明的范围内可见。此外,如果封装此新作用域的更高级别作用域中存在相同的变量名称(使用左大括号或左大括号创建),则新声明将覆盖新作用域内的先前声明。一旦新范围结束(使用右大括号或右大括号),原始声明将再次可见。
例如在下面的源代码中,第一个函数中声明的函数atof1()
的声明用于验证第二个函数中函数atof1()
的使用。此外,编译器在遇到正在使用的函数但未声明时为函数 atof2()
创建一个声明,并且此创建的声明用于对该函数的任何其他使用实例执行有效性检查 atof2()
.
int xatoi(char s[]) {
extern double atof1(char s[]); // atof is a function that takes a character array and returns a double value
extern double jj;
jj = atof1(s); // line 106
jj = atof2(s); // line 107, undeclared undefined function, compiler creates declaration, assumes function returns int
return (int)jj; // line 108
}
int xato2(char s[])
{
int kk; // line 113
jj = atof1(s); // line 114, variable jj is declared in function above but not in this one.
kk = atof1(s); // line 115, double value returned by atof1() is converted to int
kk = atof2(s); // line 116, compiler uses created declaration to check and atof2() is assumed to return an int
jj = atof1(s, 3); // line 117, this use of atof1() does not match the declaration of atof1() in function xatoi() above.
return (int)jj; // line 118
}
以上代码在 Visual Studio 2015 年生成以下警告和错误。
1>mldmodd.c(107): warning C4013: 'atof2' undefined; assuming extern returning int
1>mldmodd.c(114): error C2065: 'jj': undeclared identifier
1>mldmodd.c(114): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(115): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(117): error C2065: 'jj': undeclared identifier
1>mldmodd.c(117): warning C4020: 'atof1': too many actual parameters
1>mldmodd.c(117): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(118): error C2065: 'jj': undeclared identifier
这两个函数体代码有什么区别? (第一段代码来自《The C Programming Language》一书)
声明并使用函数与不先声明就直接使用函数有什么区别?
int atoi(char s[]) {
double atof(char s[]);
return (int) atof(s);
}
int atoi(char s[]) {
return (int) atof(s);
}
第一个源代码示例明确告诉编译器信息,编译器必须在第二个源代码示例中推断。
以下讨论假设函数 atof()
在示例中使用之前未以任何方式(包含文件等)声明或定义。
在第一个示例中,您有一个函数的显式声明 atof()
,它允许编译器执行一些检查以确保它被正确使用。
int atoi(char s[]) {
double atof(char s[]); // atof is a function that takes a character array and returns a double value
return (int) atof(s);
}
顺便说一下,我将其声明为 extern double atof(char s[]);
只是为了让人们清楚 reader 这是一个外部函数。
在第二个示例中,编译器必须推断出 atof()
是一个函数,并且它需要一个 char
数组。编译器使用源代码行和此调用中使用的参数类型来调用未定义和未声明的函数来创建函数声明。
但是编译器不知道函数的 return 值的类型,因为函数的定义不可用,因此为了完成生成的声明,编译器使用默认值 int
.
此编译器生成的声明仅为函数生成。如果使用未定义或未声明的变量,编译器将产生错误。决定它是函数(可能生成声明)还是变量(可能不生成)的关键在于名称后是否有左括号。
int atoi(char s[]) {
return (int) atof(s);
}
带有显式声明的第一个示例为编译器提供了额外的、显式的信息,允许它检查函数的使用。第二个例子,编译器必须做出假设并生成一个声明,然后用它来验证函数是否被正确使用。
这样生成的声明可能导致的一个问题是,如果第一次使用未定义和未声明的函数是不正确的,则编译器生成的声明也是不正确的,并且应该在以下源代码中以不同但正确的方式使用该函数, 编译器可能会生成警告或错误,具体取决于函数的两种用法(一种不正确,一种正确)之间的实际差异。
对于在其他源文件中使用的函数,首选过程是提供一个头文件或包含文件,该文件与包含正在使用的函数的源代码文件一起提供。在此头文件中将声明所有具有外部可见性的函数(换句话说,尚未在源文件中声明 static
)并且此头文件将与包含的目标代码或库文件一起提供编译后的函数定义。
任何使用该函数的人都会包含头文件,以便编译器检查他们是否正确使用了该函数。有一些检查是编译器无法提供或程序员可以解决的,但是有可用的函数声明可以通过编译器的静态语法检查提供基本级别的有效性检查。
一个实验
使用 Visual Studio 2015 进行试验,一旦函数被声明,即使在函数范围内,编译器也会记住该声明并使用该声明检查源文件中的任何其他使用。此外,如果在没有声明的情况下使用该函数,编译器会生成一个声明,然后检查该声明是否存在使用该函数的任何其他地方。
这种记住函数声明的行为与在函数范围内声明外部变量有点不同。外部变量声明仅在其声明的范围内可见。此外,如果封装此新作用域的更高级别作用域中存在相同的变量名称(使用左大括号或左大括号创建),则新声明将覆盖新作用域内的先前声明。一旦新范围结束(使用右大括号或右大括号),原始声明将再次可见。
例如在下面的源代码中,第一个函数中声明的函数atof1()
的声明用于验证第二个函数中函数atof1()
的使用。此外,编译器在遇到正在使用的函数但未声明时为函数 atof2()
创建一个声明,并且此创建的声明用于对该函数的任何其他使用实例执行有效性检查 atof2()
.
int xatoi(char s[]) {
extern double atof1(char s[]); // atof is a function that takes a character array and returns a double value
extern double jj;
jj = atof1(s); // line 106
jj = atof2(s); // line 107, undeclared undefined function, compiler creates declaration, assumes function returns int
return (int)jj; // line 108
}
int xato2(char s[])
{
int kk; // line 113
jj = atof1(s); // line 114, variable jj is declared in function above but not in this one.
kk = atof1(s); // line 115, double value returned by atof1() is converted to int
kk = atof2(s); // line 116, compiler uses created declaration to check and atof2() is assumed to return an int
jj = atof1(s, 3); // line 117, this use of atof1() does not match the declaration of atof1() in function xatoi() above.
return (int)jj; // line 118
}
以上代码在 Visual Studio 2015 年生成以下警告和错误。
1>mldmodd.c(107): warning C4013: 'atof2' undefined; assuming extern returning int
1>mldmodd.c(114): error C2065: 'jj': undeclared identifier
1>mldmodd.c(114): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(115): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(117): error C2065: 'jj': undeclared identifier
1>mldmodd.c(117): warning C4020: 'atof1': too many actual parameters
1>mldmodd.c(117): warning C4244: '=': conversion from 'double' to 'int', possible loss of data
1>mldmodd.c(118): error C2065: 'jj': undeclared identifier