Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.53/15: Рейтинг темы: голосов - 15, средняя оценка - 4.53
0 / 0 / 0
Регистрация: 21.05.2016
Сообщений: 19

Ошибка с extern

13.09.2019, 20:34. Показов 3480. Ответов 19
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
//main.cpp
#include <iostream>
#include <fstream>
 
using namespace std;
 
const int MAPW = 30;
const int MAPH = 28;
 
void outMap(char *a);
 
int main()
{
    char map[MAPH][MAPW];
    char buff[MAPW + 1];
    int input;
    ifstream mapIn("map.txt");
    for (int k = 0; k < MAPH; k++)
    {
        mapIn.getline(buff, MAPW + 1);
        for (int i = 0; i < MAPW; i++)
        {
            map[k][i] = buff[i];
        }
    }
    outMap(&map[0][0]);
    cin.get();
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//subfunc.cpp
#include <iostream>
 
using std::cout;
using std::cin;
using std::endl;
 
extern const int MAPW;
extern const int MAPH;
 
void outMap(char *a)
{
    for (int k = 0; k < MAPH; k++)
    {
        for (int i = 0; i < MAPW; i++)
        {
            cout << a[k * MAPW + i];
        }
        cout << endl;
    }
}
Компилятор выдает ошибку и пишет, что MAPW и MAPH в subfunc.cpp - неразрешенные внешние символы. Ошибки нет, если outMap() реализуется в main.cpp без extern или если константы передаются как аргументы функции опять же без extern. В чем именно причина ошибки и как пофиксить?
0
cpp_developer
Эксперт
20123 / 5690 / 1417
Регистрация: 09.04.2010
Сообщений: 22,546
Блог
13.09.2019, 20:34
Ответы с готовыми решениями:

Multiple definition ошибка, использую extern
Доброго времени суток. Столкнулся с проблемой, описанной в шапке темы. Замысел заключается в создании файла, где будут храниться все...

Ошибка CS0501: function must declare a body because it is not marked abstract, extern, or partial
прошу помочь исправить код выдает ошибку CS0501 вот сам код: using System; namespace Test { class Point {

Ошибка "Main() must declare a body because is not marked abstract, extern, or partial"
Не так давно начал изучать C# по книге Троелсена и столкнулся с проблемой. Вот весь фрагмент кода: using System; using...

19
Модератор
Эксперт С++
 Аватар для zss
13766 / 10960 / 6490
Регистрация: 18.12.2011
Сообщений: 29,234
13.09.2019, 20:59
А оба файла включены в один проект?
0
0 / 0 / 0
Регистрация: 21.05.2016
Сообщений: 19
13.09.2019, 21:11  [ТС]
Цитата Сообщение от zss Посмотреть сообщение
А оба файла включены в один проект?
Да, и функции из одного спокойно видны в другом
0
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
13.09.2019, 21:38
SavedowW, В файле main глобальные const переменные должны быть тоже extern
в объявлении переменной const он (extren) указывает, что переменная имеет внешнюю компоновку. Extern должны применяться ко всем объявлениям во всех файлах. (Глобальные переменные const имеют внутреннюю компоновку по умолчанию).
0
Evg
13.09.2019, 21:40

Не по теме:

Цитата Сообщение от Avaddon74 Посмотреть сообщение
Глобальные переменные const имеют внутреннюю компоновку по умолчанию
На всякий случай. Это в Си++. В Си не так

0
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
13.09.2019, 21:47
Evg, Ну мы же в плюсах, я и искал документацию на плюсы
https://docs.microsoft.com/ru-... ew=vs-2017
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
13.09.2019, 21:49
Цитата Сообщение от SavedowW Посмотреть сообщение
Компилятор выдает ошибку и пишет, что MAPW и MAPH в subfunc.cpp - неразрешенные внешние символы.
Разумеется, пишет. В С++ const автоматически подразумевает внутреннее связывание. Поэтому если вы к вашим константам хотите линковаться из других единиц трансляции, то и в определении этих констант надо явно вручную указывать внешнее связывание

C++
1
2
extern const int MAPW = 30;
extern const int MAPH = 28;
Но у вас в коде эти константы используются так, что вся эта возня со связываниями вам не нужна вообще. Правильнее было бы просто поместить их в заголовочный файл

C++
1
2
const int MAPW = 30;
const int MAPH = 28;
и включать везде, где надо.
0
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
13.09.2019, 21:57
SavedowW,
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Правильнее было бы просто поместить их в заголовочный файл
Соглашусь с предыдущим оратором и не нужны танцы с бубном, а главное не забыть вынести предварительное объявление функции так же в заголовочный, а не в файле реализации
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
13.09.2019, 22:17
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Но у вас в коде эти константы используются так, что вся эта возня со связываниями вам не нужна вообще. Правильнее было бы просто поместить их в заголовочный файл

C++
1
2
const int MAPW = 30;
const int MAPH = 28;
и включать везде, где надо.
... и даже если бы вам по какой-то причине требовалось внешнее связывание этих констант, то правильнее было бы все таки поместить их в заголовочный файл как

C++
1
2
inline extern const int MAPW = 30;
inline extern const int MAPH = 28;
0
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
14.09.2019, 10:33
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
inline extern const int MAPW = 30;
Так если в заголовочном объявляется, то ведь extern не нужен? или это в случае с inline?
Он мне вообще inline не дает применить к переменной, пишет только для функций
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
15.09.2019, 03:29
Цитата Сообщение от Avaddon74 Посмотреть сообщение
Так если в заголовочном объявляется, то ведь extern не нужен? или это в случае с inline?
Это зависит от того, что вам нужно получить.

Если вам нужна просто пара именованных констант, то тогда ни extern не нужен, ни inline не нужен.

Если же вам вдруг нужны именно глобальные const int объекты в памяти, то есть объекты, чьи адреса совпадают во всех единицах трансляции, то вам нужно внешнее связывание. Тогда: либо "классический" вариант с раздельным объявлением/определением, либо

C++
1
2
inline extern const int MAPW = 30;
inline extern const int MAPH = 28;
Преимущество inline extern варианта над "классическим" вариантом в том, что инициализаторы попадают в заголовочный файл, то есть во всех единицах трансляции компилятор знает значения этих констант.
0
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
15.09.2019, 08:38
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если же вам вдруг нужны именно глобальные const int объекты в памяти, то есть объекты, чьи адреса совпадают во всех единицах трансляции
Не понял, вы меня запутали, при чем здесь объект в памяти и разные единицы трансляции? Единицы трансляции живут отдельно только до момента компоновки, при чем здесь память? а на этапе исполнения это уже один исполняемый файл и глобальная переменная и так будет по одному адресу в памяти для всего файла или мы о разном? я вас не пойму.
0
"C with Classes"
2022 / 1404 / 523
Регистрация: 16.08.2014
Сообщений: 5,885
Записей в блоге: 1
15.09.2019, 08:49
Цитата Сообщение от Avaddon74 Посмотреть сообщение
и глобальная переменная и так будет по одному адресу в памяти для всего файла
по ходу, глобальная переменная будет у каждой единицы трансляции своя, включенная по средствам #include, тем самым их будет в исполняемом файле столько сколько включений #include (сколько единиц трансляции)
1
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
15.09.2019, 09:05
Цитата Сообщение от _stanislav Посмотреть сообщение
тем самым их будет в исполняемом файле столько сколько включений #include (сколько единиц трансляции)
Вот об этом хотелось бы почитать... Разве она не в глобальной области памяти будет размещена? тогда какие переменные попадают в эту область?
Я всегда считал, что переменные вынесенные из функций, размещенные в глобальной области, при исполнении будут размещены в глобальной области программы и когда мы их используем то подставляются только адреса к ним, а переменные внутри функций, размещаются в стеках (про кучу мы сейчас не говорим).

Добавлено через 2 минуты
А всякие static и extern'ы важны только для компоновщика, т.е. они разрешают использовать эти переменные в других файлах или нет
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
15.09.2019, 10:54
Цитата Сообщение от Avaddon74 Посмотреть сообщение
Не понял, вы меня запутали, при чем здесь объект в памяти и разные единицы трансляции?
Я говорю о вполне конкретном нюансе.

Если вы сделаете в заголовочном файле

C++
1
const int MAPW = 30;
включите его в два разных файла реализации и напечатаете из них обоих &MAPW, то вы получите разные адреса. Каждая единица трансляции получит свой отдельный объект MAPW.

Если же вы сделаете в заголовочном файле

C++
1
inline extern const int MAPW = 30;
включите его в два разных файла реализации и напечатаете из них обоих &MAPW, то вы получите одинаковые адреса. Все единицы трансляции будут видеть один глобальный объект MAPW.

Если вам по какой-то экзотической причине важно иметь разные или одинаковые адреса в этом случае - то это будет определять ваш выбор способа объявления. Обычно это не важно и автору исходного вопроса это не нужно. Но тем не менее...
1
"C with Classes"
2022 / 1404 / 523
Регистрация: 16.08.2014
Сообщений: 5,885
Записей в блоге: 1
15.09.2019, 14:29

Не по теме:

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если вам по какой-то экзотической причине важно иметь разные или одинаковые адреса в этом случае - то это будет определять ваш выбор способа объявления.
Да здравствует С++



Добавлено через 5 минут
Цитата Сообщение от Avaddon74 Посмотреть сообщение
когда мы их используем то подставляются только адреса к ним.
переменная еще может быть вставлена в инструкцию процессора непосредственно.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
15.09.2019, 14:34
Цитата Сообщение от Avaddon74 Посмотреть сообщение
Не понял, вы меня запутали, при чем здесь объект в памяти и разные единицы трансляции?
В принципе, в посте #15 уже всё написано, но на всякий случай положу пример, чтобы было перед глазами

C++
// Файл t1.cc
#include <cstdio>
#include "t.h"
 
int main (void)
{
  printf ("main: &A=%p\n", &A);
  foo ();
  return 0;
}
C++
// Файл t2.cc
#include <cstdio>
#include "t.h"
 
void foo (void)
{
  printf ("foo:  &A=%p\n", &A);
}
C++
// Файл t.h
extern void foo (void);
 
#if 1
const int A = 1;
#else
inline extern const int A = 1;
#endif
Code
$ g++-7.3.0 t1.cc t2.cc
$ ./a.out
main: &A=0x400634
foo:  &A=0x400648
Теперь в файле t.h заменим #if 1 на #if 0. В этом случае придётся добавить опцию -std=c++17, т.к. это, судя по всему, появилось только в C++17

Code
$ g++-7.3.0 t1.cc t2.cc -std=c++17
$ ./a.out
main: &A=0x400634
foo:  &A=0x400634
-----------------------

Если смотреть на вопрос только с точки зрения связывания (и абстрагироваться от работы с константным значением), то можно написать аналог на языке Си. Правда на "чистом" Си нет возможности навесить weak на переменную, а потому конкретно в данном примере я использовал директиву #pragma - это расширение языка, которое понимают gcc и многие другие компиляторы (т.е. с самого раннего этапа появления языка Си наблюдалась нехватка этой возможности)

C
/* Файл t1.c */
#include <stdio.h>
#include "t.h"
 
int main (void)
{
  printf ("main: &A=%p\n", &A);
  foo ();
  return 0;
}
C
/* Файл t2.c */
#include <stdio.h>
#include "t.h"
 
void foo (void)
{
  printf ("foo:  &A=%p\n", &A);
}
C
/* Файл t.h */
extern void foo (void);
 
#if 1
static int A = 1;
#else
#pragma weak A
int A = 1;
#endif
Code
$ gcc-7.3.0 t1.c t2.c
$ ./a.out
main: &A=0x600930
foo:  &A=0x600934
Теперь в файле t.h заменим #if 1 на #if 0

Code
$ gcc-7.3.0 t1.c t2.c
$ ./a.out
main: &A=0x600930
foo:  &A=0x600930
1
 Аватар для Avaddon74
571 / 353 / 133
Регистрация: 15.09.2017
Сообщений: 1,239
15.09.2019, 17:50
TheCalligrapher, Evg, Мдаа, ребят, не знал! Спасибо, что объяснили. А для каких целей это сделано, зачем её разделять на каждую трансляцию? Это ведь не эффективно с точки зрения памяти.
0
Evg
Эксперт CАвтор FAQ
 Аватар для Evg
21281 / 8305 / 637
Регистрация: 30.03.2009
Сообщений: 22,660
Записей в блоге: 30
15.09.2019, 18:30
Цитата Сообщение от Avaddon74 Посмотреть сообщение
зачем её разделять на каждую трансляцию?
Это к стандарту языка не относится. Как пожелает автор программы, так оно и будет. А язык программирования лишь предоставляет для этого возможности (конкретно в данном случае для Си и Си++ оказалось, что ещё и синтаксис разный). В данной теме по сути шло обсуждение того, как правильно пользоваться этими возможностями, а вовсе не о том, как отстрелить себе фаберже, написав г-код
2
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
12919 / 6787 / 1817
Регистрация: 18.10.2014
Сообщений: 17,169
15.09.2019, 21:42
Цитата Сообщение от Avaddon74 Посмотреть сообщение
А для каких целей это сделано, зачем её разделять на каждую трансляцию? Это ведь не эффективно с точки зрения памяти.
Константы скалярных типов, вроде const int в 99% случаев используются так, как в коде у автора исходного вопроса. Такие константы вообще не требуют индивидуального физического размещения в памяти (в памяти переменных). Поэтому вопрос "эффективности с точки зрения памяти" тут не возникает вообще. Об этом даже задумываться не нужно.

Вопросы размещения в памяти начинают играть роль, как только вы начинаете использовать эти константы как lvalue, т.е. например применять к ним &. И тут уже все определяется тем, что именно вы хотите получить в результате.

Вопросы размещения в памяти также начинают играть роль, когда речь заходит о константах существенно более тяжелых типов. И тут уже действительно: становится неуместным бездумно клепать копии таких констант в каждой единице трансляции.
1
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
raxper
Эксперт
30234 / 6612 / 1498
Регистрация: 28.12.2010
Сообщений: 21,154
Блог
15.09.2019, 21:42
Помогаю со студенческими работами здесь

Узнать хендл окна: ошибка Недопустимый для этого элемента модификатор "extern"
Здравствуйте, не могу узнать хендл окна. В коде написал следующее: using System.Runtime.InteropServices; public static extern...

Ошибка при использовании extern: "Это объявление не содержит класс хранения или спецификатор типа"
main.c int test = 10; int main(){ return 0; } test.c extern int test; test = 20;//почему тут ошибка, это объявление не...

Что означает extern "C" или extern "C++"?
Например такой код, extern &quot;C&quot; void f(); Или C++ вместо C. Что это означает и где это применяется ?:)

Ошибка "avtos.avtos()" должен объявлять тело, т.к. он не помечен модификатором abstract, extern, или partial
Пишу прогу с классом , где переменные с параметром private , и выдаёт ошибку . Ошибка &quot;ConsoleApplication1.avtos.avtos()&quot;...

extern
Всем привет, читал сейчас библиотеку SDL и там встретил такой вот код: extern &quot;C&quot; { //... } Так вот...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
Новые блоги и статьи
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 05.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 17.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
Фото: Daniel Greenwood
kumehtar 13.11.2025
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru