在C中的函数内声明函数
我正在读KR C的书,我面对一个我不理解的函数定义。这是第87页的在C中的函数内声明函数,c,C,我正在读KR C的书,我面对一个我不理解的函数定义。这是第87页的qsort()函数。它在qsort()函数中声明swap()函数: void qsort(args) { ... void swap(arguments); ... swap(a,b); } void swap(arguments){ ... } swap()函数不应该在函数之外声明吗?为什么要在qsort()函数中声明它?我想您正在阅读K&R C编程语言,也许还有ANSI C的第二版?在第87页有一个PDF,上面讨论
qsort()
函数。它在qsort()函数中声明swap()
函数:
void qsort(args)
{
...
void swap(arguments);
...
swap(a,b);
}
void swap(arguments){
...
}
swap()
函数不应该在函数之外声明吗?为什么要在qsort()
函数中声明它?我想您正在阅读K&R C编程语言,也许还有ANSI C的第二版?在第87页有一个PDF,上面讨论了使用快速排序算法的递归
请参阅此Wikipedia主题,比较和对比各种C标准
K&R C图书为旧式C,第二版版权为1988年。那里有很多很好的材料,但是需要从旧样式的角度来阅读,而且C标准自ANSI C以来已经发生了变化。主要的事情是更好地说明编译器应该声明哪些错误和警告。在ANSIC中有一些东西是完全可以接受的,但在现代C标准中已经不可接受了。通过收紧C编程语言规范并提供一些额外的关键字和语法,大量工作已经投入到试图通过编译器提供更好的静态检查上
swap()
应该有一个转发声明,或者函数的定义及其源代码应该在函数实际使用之前出现。这允许C编译器根据函数的声明或定义检查函数的使用情况,以检查可能的使用错误
但是,对于C编程语言,如果在定义或声明函数之前使用该函数,通常会从Visual Studio 2013warning C4013中得到一条警告,如此警告:“swap”未定义;假设外部程序返回int
一些编译器(最近版本的clang
和gcc
以及Visual Studio 2015)已经开始实现C11。某些编译器提供了其他选项来改进警告和/或将某些类型的警告转化为错误
例如,如果我在testit.c文件中有以下源代码(注意c源代码的.c文件扩展名),并使用Visual Studio 2013使用4级警告进行编译,我将得到一组警告,但没有错误。VisualStudio使用C的标准和规则编译C源,这比C++的更为松散,即使是相同的语法。
我编译了这个源代码的两个不同版本,一个在第2行注释掉了forward声明,另一个未注释。从警告中注意到,VisualStudio的C编译器允许在不使用前向声明的情况下使用函数
请注意,在第二次运行中,当第2行上的前向声明未注释时,会出现一条关于为函数范围内的函数提出前向声明的警告:警告C4210:使用了非标准扩展名:函数给定文件范围
还请注意,通过在第二次运行中提供转发声明,编译器能够识别可能的使用错误并发出警告,在一种情况下发出实际错误
请注意,参数的数量在第一次和第二次编译中都有所不同,但只有在前向声明未注释且可供编译器使用的第二次编译中,我们才会看到有关额外参数的警告
int func1() { // line 1
// int swap(int a, int b); // line 2, forward declaration for function swap
int j = swap(1, 2);
return 0;
}
int func2() { // line 9
struct {
int a;
int b;
int c;
} mm = { 0 };
int k = swap(4, 5, 8); // line 16
float ff = swap(4.0, 5.0, 8.0); // line 18
int k2 = swap(mm, 2, 3); // line 20
return 1;
}
int swap(int a, int b) { // line 25
return a + b;
}
警告如下:
1>------ Build started: Project: ConsoleApplication3, Configuration: Debug Win32 ------
1> testit.c
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4013: 'swap' undefined; assuming extern returning int
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'initializing' : conversion from 'int' to 'float', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(16): warning C4189: 'k' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4189: 'k2' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4189: 'ff' : local variable is initialized but not referenced
1> ConsoleApplication3.vcxproj -> C:\Users\Projects\Debug\ConsoleApplication3.exe
如果随后取消对函数swap()
的正向声明的注释,我将看到以下编译器输出的警告和错误:
1>------ Build started: Project: ConsoleApplication3, Configuration: Debug Win32 ------
1> testit.c
1>c:\users\projects\consoleapplication3\testit.c(2): warning C4210: nonstandard extension used : function given file scope
1>c:\users\projects\consoleapplication3\testit.c(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit.c(16): warning C4020: 'swap' : too many actual parameters
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'function' : conversion from 'double' to 'int', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4020: 'swap' : too many actual parameters
1>c:\users\projects\consoleapplication3\testit.c(18): warning C4244: 'initializing' : conversion from 'int' to 'float', possible loss of data
1>c:\users\projects\consoleapplication3\testit.c(20): error C2440: 'function' : cannot convert from '' to 'int'
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4024: 'swap' : different types for formal and actual parameter 1
1>c:\users\projects\consoleapplication3\testit.c(20): warning C4020: 'swap' : too many actual parameters
现在C++编程语言不同,不允许这种松散。这就是为什么C++与C共享历史,C++是一种不同的相关语言。
如果我将相同的源代码复制到文件testit2.cpp中,那么编译时会看到不同的错误
首先,将swap()
的转发声明注释掉
1> testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C3861: 'swap': identifier not found
再次声明未注释的转发
1> testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C3861: 'swap': identifier not found
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C3861: 'swap': identifier not found
最后,如果我将swap()
的前向声明从函数func1()
的作用域移到文件作用域中,使其现在是第1行,那么我将看到以下不同的错误:
1> testit2.cpp
1>c:\users\projects\consoleapplication3\testit2.cpp(4): warning C4189: 'j' : local variable is initialized but not referenced
1>c:\users\projects\consoleapplication3\testit2.cpp(16): error C2660: 'swap' : function does not take 3 arguments
1>c:\users\projects\consoleapplication3\testit2.cpp(18): error C2660: 'swap' : function does not take 3 arguments
1>c:\users\projects\consoleapplication3\testit2.cpp(20): error C2660: 'swap' : function does not take 3 arguments
我想您正在阅读K&R C编程语言,也许是ANSI C的第二版?在第87页有一个PDF,上面讨论了使用快速排序算法的递归
请参阅此Wikipedia主题,比较和对比各种C标准
K&R C图书为旧式C,第二版版权为1988年。那里有很多很好的材料,但是需要从旧样式的角度来阅读,而且C标准自ANSI C以来已经发生了变化。主要的事情是更好地说明编译器应该声明哪些错误和警告。在ANSIC中有一些东西是完全可以接受的,但在现代C标准中已经不可接受了。通过收紧C编程语言规范并提供一些额外的关键字和语法,大量工作已经投入到试图通过编译器提供更好的静态检查上
swap()
应该有一个转发声明,或者函数的定义及其源代码应该在函数实际使用之前出现。这允许C编译器根据函数的声明或定义检查函数的使用情况,以检查可能的使用错误
但是,对于C编程语言,如果在定义或声明函数之前使用该函数,通常会从Visual Studio 2013warning C4013中得到一条警告,如此警告:“swap”未定义;假设外部程序返回int
一些编译器(最近版本的clang
和gcc
以及Visual Studio 2015)已经开始实现C11。一些编译器提供了额外的