Повторное определение main linux

Русские Блоги

Перепечатка: повторное включение заголовочного файла и определение переменной

Перепечатка: повторное включение заголовочного файла и определение переменной

В c или c ++ повторное включение заголовочных файлов — это проблема, которую программисты должны избегать, а также проблема, связанная с тем, что многие новички склонны совершать ошибки.
Почему мы должны избегать повторного включения заголовочных файлов?

1. Мы знаем, что при компиляции программы на c или c ++ компилятор должен сначала предварительная обработка Одна из задач предварительной обработки состоит в том, чтобы полностью развернуть файл заголовка #include в исходной программе. Если вы включаете один и тот же файл заголовка несколько раз, преднамеренно или непреднамеренно, это заставит компилятор Compile Шаги по компиляции заголовочного файла несколько раз, объем инженерного кода невелик, но большое количество инженерных решений замедлит скорость компиляции всего проекта, и последующее обслуживание и модификация станут трудными.

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

Давайте посмотрим на пример:

В это время введите gcc -c main.c для компиляции, он предложит А повторить определение, и программа вылетает:

Затем введите gcc -E main.c -o main.i, чтобы увидеть содержимое предварительной обработки:

Вы можете видеть, что строки 6015 и 6021 повторяются int A=1; Определение S нарушает принцип одного определения, поэтому оно пойдет не так.

Понять недостатки повторного включения заголовочных файлов, так как этого избежать?
Обычно есть два подхода: Условная компиляция с #pragma once
Условная компиляция распространена
#ifndef _XXX
#define _XXX
.
#endif
Как это можно использовать в Google. Здесь вводит #pragma один раз: #pragma once Этот метод уникален для компилятора Microsoft и только позже, поэтому не так много людей знают и не так много людей, потому что он не поддерживает кроссплатформенность. Если вы хотите написать кроссплатформенный код, лучше всего использовать условную компиляцию. Если вы хотите использовать #pragma один раз, просто добавьте #pragma один раз в начале файла заголовка.
Связь и разница между ними:
Контакты могут избегать повторного включения заголовочных файлов, разница состоит в основном в двух способах избежать повторного включения заголовочных файлов.
Посмотрите на приведенный выше пример еще раз:
Без учета b.h измените main.c на:

Читайте также:  Linux создать исполняемый файл python

Рассмотрим случай 1 условной компиляции:

При компиляции main.c этап предварительной обработки встретился с ①, компилятор открыл ах и обнаружил, что _A_H не был определен, поэтому содержимое между #define и #endif было включено в main.c; при обнаружении, компилятор снова Откройте ах и найдите, что _A_H был определен, поэтому закройте ах напрямую, ах снова не включается в main.c, что позволяет избежать повторного включения.
Рассмотрим вариант 2 прагмы один раз:
Когда stage встречается на этапе предварительной обработки, откройте a.h, включите содержимое после #pragma один раз в main.c и закройте a.h. Когда он встречает ②, компилятор пропускает оператор напрямую и выполняет следующий оператор, чтобы избежать повторного включения.

После разговора о повторном включении файлов давайте подумаем о проблеме: как уже упоминалось ранее, избегание повторного включения заголовочных файлов может эффективно избежать повторного определения переменных. На самом деле, это не только повторение переменных Определения могут также избегать повторных определений функций, классов и структур. но
Необходимо ли избегать повторного включения заголовочных файлов, чтобы избежать повторного определения переменных, функций, классов и структур?
Ответ, конечно же, нет!
Давайте посмотрим на приведенный выше пример еще раз:

Затем скомпилируйте gcc -c b.c -o b.o и gcc -c main.c -o main.o отдельно без каких-либо ошибок.
Но когда генерируется исполняемый файл gcc b.o main.o -o main, компилятор выдает ошибку:

Почему это пошло не так? В соответствии с условной компиляцией, a.h не включается многократно, но он по-прежнему предлагает многократно определять переменную A.
Здесь следует обратить внимание на повторное определение переменных, функций, классов, структур Происходит не только при компиляции исходной программы, но и при связывании целевой программы , Мы знаем, что основной единицей компиляции c / c ++ является файл .c или .cpp, и компиляция каждой базовой единицы не зависит друг от друга. Условная компиляция, такая как #ifndef, может быть гарантирована только в одной базовой единице (отдельный файл .c или .cpp) Файл заголовка не будет повторно скомпилирован, но нет гарантии, что один и тот же файл заголовка в двух или более базовых модулях не будет повторно скомпилирован, не так ли? Неважно, давайте возьмем пример только сейчас:
gcc -c bc -o bo: файл bc скомпилирован в файл bo. В этом процессе компилятор все равно откроет файл ah на этапе предварительной обработки, определит _A_H и включит ah до н.э.
Файл gcc -c cc -o co: cc компилируется в файл co. В этом процессе обратите внимание на этап предварительной обработки. Компилятор по-прежнему открывает файл ah. В настоящее время выполняется _A_H Это было определено? Как упоминалось ранее, компиляция несвязанных файлов .c не зависит друг от друга. Естественно, компиляция b.c не повлияет на процесс компиляции c.c, поэтому _A_H в c.c не будет зависеть от _A_H в b.c, то есть _A_H в c.c не определено ! ! Таким образом, компилятор сделал то же самое снова, определив _A_H, включая _A_H.
На данный момент у нас есть b.o и c.o, после компиляции main.c у нас есть main.o, а затем связывание их для генерации main имеет проблему:
Когда компилятор компилирует файлы .c или .cpp, существует важный шаг, который заключается в Уже определенные переменные выделяют пространство памяти В A.h A является определенной переменной, поскольку b.c и c.c независимы, A эквивалентно двойному определению и выделению двух разных областей памяти. Когда main.o связывает b.o и c.o, так как основная функция вызывает функции fb и fc, эти две функции вызывают переменную A. Для основной функции Переменная должна быть уникальной и должна быть только область памяти , Но A в fb и fc выделяется разная память, адрес памяти разный, основная функция не может определить, какой адрес находится в A, неоднозначность , Так что программа пойдет не так.

Читайте также:  Astra linux журнал аудита

Сказав так много, как мы можем избежать повторных определений?
На самом деле, ключом к тому, чтобы избежать повторных определений, является Избегайте повторной компиляции Предотвратить повторное включение заголовочных файлов — это эффективный способ избежать повторной компиляции, но лучше всего запомнить это предложение: Заголовочный файл должен иметь только утверждение, без определения , Это не только уменьшает зависимости компиляции между файлами, уменьшает время и производительность, вызванные компиляцией, но, что более важно, предотвращает появление двойных определений и предотвращает сбои программы.

Источник

Взаимодействие между потоками, повторное определение

Многопоточное приложение и взаимодействие между потоками
Здравствуйте! Подскажите, пожалуйста, как в Qt сделать 3-х поточного клиента, один поток которого.

Взаимодействие между потоками
Привет. Есть класс А, который содержит не статические методы, которые можно вызвать лишь с главного.

Взаимодействие между потоками
Здравствуйте уважаемые форумчане. Уже много лет не обращался к вам за помощью, сам разбирался и.

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

инклюдят заголовочные файлы, а не source файлы.
если не вдаваться в ваш код и задачу ,
не хватает заголовочных файлов OpenConnection.h, thread.h и Session.h

#pragma once void OpenConnection();
#include "OpenConnection.h" #include "Communication.h" #include void OpenConnection() { // --------

Тоже с Session.h и thread.h

Добавлено через 4 минуты

ЦитатаСообщение от Tny2 Посмотреть сообщение

#include #include "thread.h" int main() { OpenChatThreads(); return 0; }

то препроцессор скопирует и вставит код из thread.c в main.c .

Функция OpenChatThreads() будет определена и в thread.c и в main.c.
Компилятор создаст объектный код thread.o и main.o.
А линковщик споткнется, потому что функция OpenChatThreads() определена и там и там.

ЦитатаСообщение от Tny2 Посмотреть сообщение

1) Определение WaitedSessionClient должно находиться в *.c файле (например, Communication.c):
Communication.h:

#pragma once struct CommunicationThread { int socket; }; extern struct CommunicationThread WaitedSessionClient;
#include "Communication.h" struct CommunicationThread WaitedSessionClient = { .socket = 0, };

Взаимодействие между потоками
Мне надо чтоб 1 поток перебирал числа из файла и , которые кратны 17, передавать второму потоку.

Взаимодействие между потоками и зсувками
Написать параллельную программу с общей переменной типа integer и двумя рабочими процессами.

Взаимодействие с потоками
Вызывающий поток не может получить доступ к данному объекту, так как владельцем этого объекта.

Повторное определение классов
Есть несколько форм в которых заполняются данные в объекте одного из классов. Есть базовый класс и.

Повторное определение вектора
Почему можно написать vector<int> g(n, 8); , когда g — уже определенная глобальная переменная, и.

Повторное определение класса
проверьте на правильность написания, выдает ошибки #include<iostream> #include"MyClass.h".

Как некоторые компиляторы игнорируют повторное определение static local vars?
День добрый, искал на других сайтах ответы на этот вопрос, но так и не понял. Сказано, что.

Источник

Как исправить ошибку повторного определения в GCC?

Пытаюсь скомпилировать старый код для последующего рефакторинга,
вылетает ошибка «(путь до файла) здесь повторное определение «verbosity»; build/TL/tlc-new.o:/home/user/stack/sowilo/TL/tlc-new.c:48: здесь первое определение.

У меня GCC 11.2.0
И я пытался в CFLAGS указать флаг -fcommon, но это не помогло.

вот мой Makefile, помогите пожалуйста исправить данную ошибку
https://pastebin.com/i1ykjJVG

Средний 4 комментария

cc -o build/bin/tlc-new build/TL/tlc-new.o build/TL/tl-parser-new.o build/common/kdb-data-common.o build/common/server-functions.o build/common/crc32.o -m64 -ggdb -rdynamic -lm -lrt -lcrypto -lz -lpthread
/usr/bin/ld: build/TL/tl-parser-new.o:/home/mikhail/stack/sowilo/binlog/kdb-binlog-common.h:201: повторное определение «log_schema»; build/TL/tlc-new.o:/home/mikhail/stack/sowilo/binlog/kdb-binlog-common.h:201: здесь первое определение
/usr/bin/ld: build/common/kdb-data-common.o:/home/mikhail/stack/sowilo/binlog/kdb-binlog-common.h:201: повторное определение «log_schema»; build/TL/tlc-new.o:/home/mikhail/stack/sowilo/binlog/kdb-binlog-common.h:201: здесь первое определение
/usr/bin/ld: build/common/server-functions.o:/home/mikhail/stack/sowilo/common/server-functions.c:65: повторное определение «verbosity»; build/TL/tlc-new.o:/home/mikhail/stack/sowilo/TL/tlc-new.c:48: здесь первое определение
collect2: error: ld returned 1 exit status
make: *** [Makefile:500: build/bin/tlc-new] Ошибка 1

LinuxGod, давайте код хедера. Судя по всему, у вас разные объектники с этим хедером собираются с разными флагами, из-за чего получаются 2 разных определения

Wataru, ну да, я в курсе. Но просто он определяется не только тут но и объявляется много где ещё, если добавить extern компиляция конечно продолжится, но выпадут ошибки в том месте где эти переменные берутся из common. Наверное есть ещё какой-то флаг позволяющей это делать, может я не знаю.

Источник

Оцените статью
Adblock
detector