Попытка отобразить текст через CMD с C ++, и я получаю сообщение об ошибке [duplicate]

Что такое «неопределенный ссылочный / неразрешенный внешний символ»

Я попытаюсь объяснить, что такое «неопределенный ссылочный / неразрешенный внешний символ».

note : я использую g ++ и Linux, и все примеры для него

Например, у нас есть некоторый код

// src1.cpp
void print();

static int local_var_name; // 'static' makes variable not visible for other modules
int global_var_name = 123;

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

и

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
//extern int local_var_name;

void print ()
{
    // printf("%d%d\n", global_var_name, local_var_name);
    printf("%d\n", global_var_name);
}

Создание объектных файлов

$ g++ -c src1.cpp -o src1.o
$ g++ -c src2.cpp -o src2.o

После фазы ассемблера у нас есть объектный файл, который содержит любые экспортируемые символы. Посмотрите на символы

$ readelf --symbols src1.o
  Num:    Value          Size Type    Bind   Vis      Ndx Name
     5: 0000000000000000     4 OBJECT  LOCAL  DEFAULT    4 _ZL14local_var_name # [1]
     9: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_var_name     # [2]

Я отклонил некоторые строки из вывода, потому что они не имеют значения

Итак, мы видим следующие символы для экспорта.

[1] - this is our static (local) variable (important - Bind has a type "LOCAL")
[2] - this is our global variable

src2.cpp ничего не экспортирует, и мы не видели его символов

Свяжите наши объектные файлы

$ g++ src1.o src2.o -o prog

и запустите его

$ ./prog
123

Linker видит экспортированные символы и связывает их. Теперь мы пытаемся раскомментировать строки в src2.cpp, как здесь

// src2.cpp
extern "C" int printf (const char*, ...);

extern int global_var_name;
extern int local_var_name;

void print ()
{
    printf("%d%d\n", global_var_name, local_var_name);
}

, и перестроить объектный файл

$ g++ -c src2.cpp -o src2.o

OK (нет ошибок), потому что мы только строим объектный файл, связь еще не завершена. Попробуйте установить ссылку

$ g++ src1.o src2.o -o prog
src2.o: In function `print()':
src2.cpp:(.text+0x6): undefined reference to `local_var_name'
collect2: error: ld returned 1 exit status

Это произошло потому, что наше local_var_name статично, то есть оно не отображается для других модулей. Теперь глубже. Получить выход фазы перевода

$ g++ -S src1.cpp -o src1.s

// src1.s
look src1.s

    .file   "src1.cpp"
    .local  _ZL14local_var_name
    .comm   _ZL14local_var_name,4,4
    .globl  global_var_name
    .data
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; assembler code, not interesting for us
.LFE0:
    .size   main, .-main
    .ident  "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
    .section    .note.GNU-stack,"",@progbits

Итак, мы видели, что для local_var_name нет метки, поэтому линкер не нашел его. Но мы хакеры :), и мы можем это исправить. Откройте src1.s в текстовом редакторе и измените

.local  _ZL14local_var_name
.comm   _ZL14local_var_name,4,4

на

    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789

i.e. вам должно быть как ниже

    .file   "src1.cpp"
    .globl  local_var_name
    .data
    .align 4
    .type   local_var_name, @object
    .size   local_var_name, 4
local_var_name:
    .long   456789
    .globl  global_var_name
    .align 4
    .type   global_var_name, @object
    .size   global_var_name, 4
global_var_name:
    .long   123
    .text
    .globl  main
    .type   main, @function
main:
; ...

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

$ g++ -c src1.s -o src2.o

ok, см.

$ readelf --symbols src1.o
8: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 local_var_name

В настоящее время local_var_name имеет привязку GLOBAL (LOCAL)

link

$ g++ src1.o src2.o -o prog

и запускает ее

$ ./prog 
123456789

ok, мы взломаем его:)

Итак, в результате - «неопределенная ссылка / неразрешенная внешняя ошибка символа» происходит, когда компоновщик не может найти глобальные символы в объектных файлах.

369
задан sorin 5 August 2013 в 23:05
поделиться

15 ответов

Если вы запускаете без отладки (Ctrl + F5), то по умолчанию он предлагает вам нажать return, чтобы закрыть окно. Если вы хотите использовать отладчик, вы должны поставить точку останова на последней строке.

386
ответ дан Tom 28 August 2018 в 02:43
поделиться

Использовать:

  1. cin.get();

или

  1. system("pause");

Обязательно сделайте любой из них в конце функции main() и перед оператором return.

1
ответ дан Ahmed 28 August 2018 в 02:43
поделиться

попытайтесь вызвать getchar() прямо перед возвратом main().

11
ответ дан Alex Shesterov 28 August 2018 в 02:43
поделиться

Просто нажмите CNTRL + F5, чтобы открыть его во внешнем окне командной строки (Visual Studio не контролирует его).

Если это не работает, добавьте следующее в конец вашего Код:

Console.WriteLine("Press any key to exit...");
Console.ReadKey();

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

Если вы хотите сделать это в нескольких местах, поместите вышеуказанный код в метод (например, private void Pause()) и вызовите Pause() всякий раз, когда программа достигает возможного конца.

42
ответ дан carefulnow1 28 August 2018 в 02:43
поделиться

Если вы используете .NET, поставьте Console.ReadLine() до конца программы.

Он будет ждать <ENTER>.

17
ответ дан Cheeso 28 August 2018 в 02:43
поделиться

Вот решение, которое (1) не требует каких-либо изменений кода или точек останова, и (2) приостанавливает после завершения программы , чтобы вы могли видеть все , которые были распечатаны. Он остановится после F5 или Ctrl + F5. Основной недостаток заключается в том, что на VS2013 Express (как проверено) он не загружает символы, поэтому отладка очень ограничена.

  1. Создайте командный файл. Я назвал мой runthenpause.bat со следующим содержимым:
    %1 %2 %3 %4 %5 %6 %7 %8 %9
    pause
    
    Первая строка будет запускать любую команду, которую вы предоставляете, и до восьми аргументов. Вторая строка будет ... пауза.
  2. Откройте свойства проекта | Конфигурационные свойства | Отладка.
  3. Измените «Аргументы команд» на $(TargetPath) (или что-то в «Команде»).
  4. Измените «Команда» на полный путь до runthenpause.bat.
  5. Нажмите OK.

Теперь, когда вы запустите, runthenpause.bat запустит ваше приложение и после того, как ваше приложение завершится, приостановит вас, чтобы увидеть вывод консоли.

Я опубликую обновление, если выясню, как загрузить символы. Я пробовал /Z7 за этот , но безуспешно.

7
ответ дан Community 28 August 2018 в 02:43
поделиться

Щелкните правой кнопкой мыши по вашему проекту

Свойства> Свойства конфигурации> Коннектор> Система

выберите Консоль (/ SUBSYSTEM: CONSOLE) в опции SubSystem ,

Теперь попробуйте ... он должен работать

160
ответ дан D_D 28 August 2018 в 02:43
поделиться

(/ SUBSYSTEM: CONSOLE) не работал для моего vs2013 (у меня его уже было).

«работать без отладки» не является параметром, так как я не хочу переключаться между отладкой и просмотром output.

Я закончил с

int main() {
  ...
#if _DEBUG
  LOG_INFO("end, press key to close");
  getchar();
#endif // _DEBUG
  return 0;
}

Решение, используемое в qtcreator до 2.6. Теперь, когда qt растет, vs идет другим путем. Насколько я помню, в vs2008 нам не нужны такие трюки.

9
ответ дан fantastory 28 August 2018 в 02:43
поделиться

Вы можете запустить исполняемый файл из командной строки. Таким образом, вы можете увидеть весь вывод. Или вы можете сделать что-то вроде этого:

int a = 0;
scanf("%d",&a);

return YOUR_MAIN_CODE;

, и таким образом окно не будет закрываться, пока вы не введете данные для переменной a.

2
ответ дан Geo 28 August 2018 в 02:43
поделиться

Несколько лучшее решение:

atexit([] { system("PAUSE"); });

в начале вашей программы.

Плюсы:

  • может использовать std :: exit ()
  • может иметь несколько возвратов из основного
  • , вы можете запустить свою программу под отладчиком
  • Независимо от IDE (+ независимая от ОС, если вы используете cin.sync(); cin.ignore(); system("pause");)

Минусы:

  • должны изменить код
  • не будут останавливаться на std :: terminate ()
  • все равно произойдет в вашей программе за пределами сеанса IDE / отладчика; вы можете предотвратить это в Windows, используя:

extern "C" int __stdcall IsDebuggerPresent(void);
int main(int argc, char** argv) {
    if (IsDebuggerPresent())
        atexit([] {system("PAUSE"); });
    ...
}
1
ответ дан GhassanPL 28 August 2018 в 02:43
поделиться

Visual Studio 2015 с импортом. Потому что я ненавижу, когда примеры кода не дают необходимых импортов.

#include <iostream>;

int main()
{
    getchar();
    return 0;
}
-2
ответ дан J.M.I. MADISON 28 August 2018 в 02:43
поделиться

Перейти к меню отладки -> Нажмите StartWithoutDebugging

24
ответ дан pashaplus 28 August 2018 в 02:43
поделиться

просто введите вашу последнюю строку кода:

system("pause");
2
ответ дан rafraph 28 August 2018 в 02:43
поделиться

Используйте console.readline. Ваш пишет строку, но не читает ее.

-3
ответ дан taskinoor 28 August 2018 в 02:43
поделиться

добавить "| pause "в поле аргументов команды в разделе отладки в свойствах проекта.

2
ответ дан theambient 28 August 2018 в 02:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: