2016-09-14 2 views
0

Я читаю книгу KR C, и я сталкиваюсь с определением функции. Я не понимаю. Это функция qsort(). Он объявляет функцию swap() внутри qsort() функции:Объявление функции внутри функции в C

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

void swap(arguments){ 
... 
} 

не должен swap() функций объявляются вне функции? Зачем объявлять его внутри функции qsort()?

+3

Вы не можете использовать функцию, которая не объявлена. Не имеет особого значения, когда вы объявляете это, пока вы его объявляете, прежде чем использовать его, и объявление находится в области видимости. – Tibrogargan

+0

Разве это не область, ограниченная внутри блока, где определено? В этом случае 'swap()' действует только в 'qsort()' function – Arash

+0

@Arash Да. И в части файла после его определения тоже, конечно. Потому что объявление является объявлением. – hyde

ответ

7

Я полагаю, что вы читаете язык программирования программирования K & R C и, возможно, второе издание с ANSI C? Существует PDF на https://hassanolity.files.wordpress.com/2013/11/the_c_programming_language_2.pdf и на странице 87 обсуждается рекурсия с использованием алгоритма быстрой сортировки.

Смотрите эту Википедии тему сравнения и сопоставления различных стандартов C https://en.wikipedia.org/wiki/ANSI_C

В K & RC книги старый стиль C как Second Edition авторское право 1988. Много хорошего материала там, но она должна быть прочитана с точки зрения более старого стиля, а стандарты C изменились с ANSI C. Главное, что лучше сказать, какие компиляторы должны объявлять как ошибки и предупреждения. В ANSI C были абсолютно приемлемы вещи, которые более неприемлемы для современных стандартов C. Большая часть работы была направлена ​​на то, чтобы обеспечить лучшую статическую проверку компиляторами, ужесточив спецификации языка программирования C и предоставив несколько дополнительных ключевых слов и синтаксиса.

Там либо должно быть объявление вперед для swap(), либо определение функции с ее исходным кодом должно появиться до того, как функция фактически будет использоваться. Это позволяет компилятору C проверять использование функции против ее декларации или определения, чтобы проверить возможные ошибки использования.

Однако с языком программирования C, если вы используете функцию до того, как она будет определена или объявлена, вы, как правило, получите предупреждение, такое как это предупреждение от Visual Studio 2013 warning C4013: 'swap' undefined; assuming extern returning int.

Некоторые компиляторы, последние версии clang и gcc приходят на ум, а также Visual Studio 2015, начали внедрять C11. Некоторые компиляторы предоставляют дополнительные возможности для улучшения предупреждений и/или превращения некоторых видов предупреждений в ошибки.

Например, если у меня есть следующий исходный код в файле testit.c (обратите внимание на расширение файла .c для исходного кода C) и скомпилируйте с помощью Visual Studio 2013 с использованием уровня предупреждения 4, я получу набор но никаких ошибок. Visual Studio компилирует это как источник C, используя стандарты и правила для C, которые слабее, чем для C++ даже для одного и того же синтаксиса.

Я скомпилировал две разные версии этого источника: один с объявлением вперед в строке 2 закомментировал и один с ним был раскопан. Обратите внимание на предупреждения о том, что компилятор C Visual Studio позволяет использовать функцию без прямого объявления.

Уведомление о том, что во втором прогоне декларируется прямое объявление в строке 2, есть предупреждение о том, что нужно добавить объявление вперед для функции в пределах области функций: 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; 
} 

Предупреждений являются:

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 
+1

K & R 2nd edition едва ли следует за «ANSI C», что означает C90. При этом использование Visual Studio для демонстрации современного соответствия стандарту C не является лучшей идеей. Причина, по которой вы можете использовать функции в VS без прототипа, заключается в том, что компилятор VS C устарел, несовместимый дерьмо. Если вы хотите сделать современное программирование на С, держитесь подальше от книги K & R и Visual Studio. – Lundin