Откуда компилятор начинает читать - PullRequest
2 голосов
/ 27 июня 2011

Это небольшая программа:

#include <iostream>
using namespace std;

int main() {
    f();
    system("pause");
}

void f() {
    static int x = 20 ;
    class tester {
    public :
        tester() {
            cout << x ;
        }
    } x1;
}

Я получаю здесь ошибку: Ошибка C3861: 'f': идентификатор не найден

Если япоместите функцию f над главной, я получу желаемый результат.

Почему это так? Мне сказали, что выполнение программы начинается с main.В соответствии с этим код должен выполняться и в первом случае.

Как компилятор начинает читать программу?

Ответы [ 6 ]

7 голосов
/ 27 июня 2011

Мне сказали, что выполнение программы начинается с основного.

И в этом все дело.

Компилятор запускается с main, а затем видит вызов f(), с которым он до сих пор не сталкивался (как он определен позже), поэтому он не знает, что с ним делать.

Если вы хотите определить f после main, вы можете поместить прототип функции раньше, например

#include <iostream>
using namespace std;

void f(); // <--- This tells the compiler that a function name f will be defined

int main() {
f();
system("pause");
}

void f() {
static int x = 20 ;
class tester {
public :
    tester() {
        cout << x ;
    }
} x1;
}
6 голосов
/ 27 июня 2011

Начало компиляции и начало выполнения программы - это две разные вещи.

Выполнение начинается с main.

Компиляция начинается с начала файла; компилятор не «перепрыгивает» файл, чтобы найти нужные фрагменты, но он считывает входные данные линейно (я подозреваю, что это связано, помимо прочего, с тем, что грамматика C ++ действительно сложна).

Когда компилятор в какой-то момент разбирает файл, он знает только то, что было объявлено / определено до этого момента 1 .

В связи с этим были изобретены прототипы функций (и вообще не определяющие объявления): прототипы всех функций , определенных в файле, помещаются в начало файл, обычно после директив #include или в отдельном включаемом файле. Прототипы сообщают компилятору, что такие функции будут определены позже, и какова сигнатура функции (то есть имя, параметры, возвращаемое значение).

Прототип выполнен как обычная функция, но без тела, которое заменяется точкой с запятой 2 . Например, в вашем коде вы должны написать

void f();

до main.

<ч />
  1. IIRC есть некоторые ограничения в этом правиле, которые позволяют компилятору "ждать" некоторых объявлений, чтобы заставить работать магию шаблона, но здесь это не имеет значения.

  2. В прототипе также часто не пишут имена параметров, оставляя только их тип (это можно сделать и в определениях функций, но это не имеет особого смысла, если у вас нет формального параметра Вы не используете). Тем не менее, я предпочитаю оставлять там имена параметров в виде документации.

3 голосов
/ 27 июня 2011

Компилятор начинается сверху и читает вниз.

вам понадобится что-то вроде:

#include <iostream>
using namespace std;

void f();

int main() {
f();
system("pause");
}

void f() {
static int x = 20 ;
class tester {
public :
    tester() {
        cout << x ;
    }
} x1;
}
3 голосов
/ 27 июня 2011

Чтобы иметь возможность вызывать функцию, она должна быть объявлена ​​в какой-то более ранней точке кода.Это просто правило языка, предназначенного для помощи компиляторам.

Вы можете объявить функцию ранее, например,

void f();

... и затем определите после основного, как вы сделали.

2 голосов
/ 27 июня 2011

Во время процесса компиляции, когда компилятор оценивает main(), ему необходимо заранее знать, что такое f(), чтобы иметь возможность сгенерировать правильный код сборки для вызова этой функции.Вот почему вам нужно поставить его перед main() в этом случае.

В качестве альтернативы вы можете объявить прототип f() до main(), чтобы компилятор знал, что это локальная функция, объявленная где-то еще в вашемфайл:

void f(); // prototype

int main() 
{
  // .. code ..
}

void f() // implementation of f()
{
 // .. code ..
}
2 голосов
/ 27 июня 2011

Нет, компилятор должен увидеть хотя бы объявление функции f () перед его использованием.Файл кода c (++) - это простой текстовый файл, который должен быть прочитан компилятором от начала до конца.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...