Блок перевода C ++ - PullRequest
       16

Блок перевода C ++

1 голос
/ 31 марта 2019

Я не совсем понял, что такое единица перевода и как использовать безымянные пространства имен:

Если у меня есть файл .cpp:

namespace
{
    void extFunction()
    {
        std::cout << "Called Unnamed Namespace's function.\n";
    }
}

и основной файл .cpp:

#include <iostream>
#include "ext.cpp"

using namespace std;

int main()
{
    extFunction();


    return 0;
}

Почему я могу получить доступ к члену Безымянного пространства имен из другого файла?

РЕДАКТИРОВАТЬ:

Спасибо за ответы;но как я могу использовать безымянные пространства имен и для каких целей?

1 Ответ

2 голосов
/ 31 марта 2019

Единица перевода - это, по сути, кусок кода, который вы даете компилятору для обработки. Компилятор обрабатывает его и создает объектный код для компоновщика. Компоновщик объединяет объектный код из всех ваших модулей перевода для формирования исполняемого файла. (Иногда вы можете увидеть детали, которые отличаются от этого, например, не видеть файл для объектного кода, когда у вас есть только одна единица перевода. Концепция остается в силе, даже если детали реализации могут отличаться.)

Так, как правило, существует взаимно-однозначное соответствие между .o (или .obj) файлами, создаваемыми при компиляции и переводе единиц измерения. Также обычно вы получаете один .o файл для каждого .cpp файла. Следовательно, обычно разумно рассматривать каждый .cpp файл как свою собственную единицу перевода. Пока не сделаешь что-то необычное.

Когда вы используете директиву #include, вы указываете компилятору заменить эту одну строку всем содержимым включенного файла. То есть кусок кода, передаваемый компилятору, включает в себя код как исходного файла, так и включенного файла. Если вы включите один файл .cpp в другой, кусок кода, передаваемый компилятору, будет включать код из двух файлов .cpp, нарушая эквивалентность между файлами .cpp и единицами перевода. Обычно это считается плохой идеей.


Давайте посмотрим на пример. Предположим, у вас есть файл с именем ext.cpp, который содержит следующее:

namespace
{
    void extFunction()
    {
        std::cout << "Called Unnamed Namespace's function.\n";
    }
}

Также предположим, что у вас есть файл с именем main.cpp, который содержит следующее:

#include <iostream>
#include "ext.cpp"


int main()
{
    extFunction();
    return 0;
}

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

[lots of code from the library header named "iostream"]
namespace
{
    void extFunction()
    {
        std::cout << "Called Unnamed Namespace's function.\n";
    }
}


int main()
{
    extFunction();
    return 0;
}

На этом этапе нет проблем с вызовом extFunction, так как компилятор видит безымянное пространство имен в фрагменте кода, который он обрабатывает.


Еще один пример запрашиваемой информации об использовании безымянных пространств имен. Похоже на вышесказанное, но отличается. Предположим, у вас есть файл с именем ext.cpp, который содержит следующее:

#include <iostream>
namespace
{
    void extFunction()
    {
        std::cout << "Called Unnamed Namespace's function in EXT.\n";
    }
}

void extPublic()
{
    extFunction();
}

Давайте также предоставим заголовок (ext.h), который объявит функцию с внешней связью.

void extPublic();

Теперь перейдите к main.cpp:

#include <iostream>
#include "ext.h"  // <-- Including the header, not the source.

namespace
{
    void extFunction()
    {
        std::cout << "Called Unnamed Namespace's function in MAIN.\n";
    }
}
int main()
{
    extFunction();
    extPublic();
    return 0;
}

Посмотри на это! Есть два определения для функции с именем extFunction! Не запутается ли компоновщик? Не за что. Эти функции не видны за пределами их единиц перевода, поэтому нет конфликта. Если вы скомпилируете main.cpp, скомпилируете ext.cpp и скомпонуете main.o и ext.o в один исполняемый файл, вы получите следующий вывод.

Вызывается функция Безымянного пространства имен в MAIN.
Вызывается функция безымянного пространства имен в EXT.

Одним из преимуществ безымянного пространства имен является то, что вам не нужно беспокоиться о конфликте с именами в безымянном пространстве имен другого исходного файла. (Это становится гораздо большим преимуществом, когда ваш проект охватывает сотни исходных файлов.)

...