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

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

Если у меня есть файл .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;
}

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

Обновлено:

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

Потому что вы #included это сделали, так что это одна и та же единица перевода. «Единица перевода» не является синонимом «файла».

Sam Varshavchik 31.03.2019 16:21
#include означает «скопировать и вставить точное содержимое файла в это место». Таким образом, ваш main.cpp скомпилирован точно так же, как если бы вы сами поместили туда безымянное пространство имен.
Yksisarvinen 31.03.2019 16:24

Никогда не включайте файл .cpp. Если бы вы не включили файл cpp и вместо этого скомпилировали его как часть своего проекта, вы бы не смогли использовать extFunction() в main.

drescherjm 31.03.2019 16:45
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
791
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Поэтому, как правило, между .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 в один исполняемый файл, вы получите следующий результат.

Called Unnamed Namespace's function in MAIN.
Called Unnamed Namespace's function in EXT.

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

Большое спасибо за помощь!

DarkoNaito_09 31.03.2019 23:09

Другие вопросы по теме