在C中的函数内声明函数

dou*_*leE 0 c

我正在阅读KR C书,我面对一个我不理解的功能定义.这是第87页的qsort()功能.它声明swap()函数内部的qsort()函数:

void qsort(args)
{
 ...
 void swap(arguments);
 ...
 swap(a,b);
}

void swap(arguments){
...
}
Run Code Online (Sandbox Code Playgroud)

swap()应该在函数之外声明函数吗?为什么在qsort()函数内声明它?

Ric*_*ers 8

我想您正在阅读K&R C编程语言,也许正在阅读ANSI C的第二版?https://hassanolity.files.wordpress.com/2013/11/the_c_programming_language_2.pdf上有PDF,第87页是使用快速排序算法的递归讨论.

请参阅此维基百科主题,比较和对比各种C标准https://en.wikipedia.org/wiki/ANSI_C

K&R C书籍是旧式C,因为第二版版权是1988年.那里有很多好的材料,但它需要从旧式的角度阅读,C标准自ANSI C以来已经改变.主要的事情是更好的关于编译器应该声明为错误和警告的规范.ANSI C中完全可以接受的东西在现代C标准中已不再可接受.通过加强C编程语言规范并提供一些额外的关键字和语法,许多工作已经尝试通过编译器提供更好的静态检查.

应该有一个前向声明,swap()或者函数的定义及其源代码应该在实际使用函数之前出现.这允许C编译器根据其声明或定义检查函数的使用情况,以检查可能的使用错误.

但是,如果在定义或声明之前使用函数,则使用C编程语言通常会从Visual Studio 2013中收到警告,例如此警告warning C4013: 'swap' undefined; assuming extern returning int.

一些编译器,最近的版本clanggcc想到的以及Visual Studio 2015,已经开始实现C11.某些编译器提供了其他选项来改进警告和/或将某些类型的警告转换为错误.

例如,如果我在文件testit.c中有以下源代码(请注意C源代码的.c文件扩展名)并使用警告级别4在Visual Studio 2013中编译,我将收到一组警告,但没有错误.Visual Studio使用C的标准和规则将其编译为C源,即使对于相同的语法,它也比C++的标准和规则更宽松.

我编译了这个源的两个不同版本,一个在第2行注释掉了前进声明,另一个在没有注释的情况下.从警告中注意到Visual Studio的C编译器允许在没有前向声明的情况下使用函数.

请注意,当第二行中的前向声明在第二次运行中取消注释时,会出现一个警告,即在函数范围内放置函数的前向声明:warning C4210: nonstandard extension used : function given file scope.

另请注意,通过第二次运行中可用的前向声明,编译器能够识别可能的使用错误并发出警告,并在一种情况下发出实际错误.

请注意,参数的数量在第一次和第二次编译中都有所不同,但仅在第二次编译时,前向声明未注释且可用于编译器,我们是否会看到有关额外参数的警告.

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;
}
Run Code Online (Sandbox Code Playgroud)

警告是:

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
Run Code Online (Sandbox Code Playgroud)

如果我然后取消注释该函数的前向声明,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
Run Code Online (Sandbox Code Playgroud)

现在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
Run Code Online (Sandbox Code Playgroud)

再次声明前进声明没有注释.

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
Run Code Online (Sandbox Code Playgroud)

最后,如果我将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
Run Code Online (Sandbox Code Playgroud)