Лучшие онлайн компиляторы

Использование GDB

Как только мы зашли в GDB нам выводится следующее сообщение:

Последняя строка говорит о том, нормально ли запустился файл.

Теперь нужно посмотреть, где в нашем файле точка вхождения (строка, откуда наша программа начинает свою работу), в случае cpp это метод . Находим номер этой строки c помощью команды и пишем её порядковый номер с буквой (также можно просто указать имя функции тоже работает):

Далее запускаем программу с помощью комманды :

Также вы можете включить TUI, с помощью комбинации клавиш <Ctrl-x a>

Для того, чтобы посмотреть на какой мы сейчас строке, нужно написать :

Для того, чтобы сделать шаг, нужно нажать (от слова next):

Как мы видим GDB сразу пропускает пустые строки (или строки с комментариями) и переходит к следующей строке.
Предположим, что у нас есть функция, при нажатии наш отладчик быстро пройдет функцию, не заходя в неё, чтобы зайти в функцию нужно сделать «шаг внутрь» (step-in) или просто клавиша :

(В примере нет функции, однако шаг step-in все равно будет работать и с обычными инициализациями, условиями и циклами)

Чтобы узнать какие переменные (локальные) сейчас инициализированны в программе нужно написать комманду :

Чтобы вывести только одну переменную, нужно написать :

Мы можем также изменить переменную с помощью :

Мы можем также следить за переменными с помощью :

Также, если нужно можно посмотреть что в данный момент находится в регистрах ():

Чтобы посмотреть какие в данный момент есть breakpoints (точки останова) нужно написать :

Чтобы удалить точку останова :

Чтобы прыгнуть к следующей точке останова нужно нажать :

Мы можем вызывать функции из программы (локальные) с помощью :

Чтобы продолжить выполнение функции и остановить программу когда она (функция) завершится нужно написать или :

Стоит уточнить, что нельзя использовать в главном методе.

Чтобы завершить выполнение программы, нужно написать :

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

Парсинг строки

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

Теперь всё, что нам нужно сделать — разбить строку на части, используя пробелы в качестве разделителей. Это значит, что мы можем использовать классическую библиотечную функцию .

Реализация этой функции подозрительно похожа на , и это неспроста! Здесь используется та же стратегия, только вместо нуль-терминированного массива символов мы используем нуль-терминированный массив указателей.

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

При необходимости мы перераспределим массив указателей. Повторяем процесс до тех пор, пока не перестанет возвращать токены, и завершаем массив токенов нуль-терминатором.

Теперь у нас есть массив токенов, готовых к исполнению.

Базовый цикл командной оболочки

В первую очередь нам нужно подумать о том, как программа должна запускаться

И здесь важно понимать, что делает оболочка во время цикла. Простой способ обработки команд состоит из трех шагов:

  1. Чтение: считывание команды со стандартных потоков.
  2. Парсинг: распознавание программы и аргументов во входной строке.
  3. Исполнение: запуск распознанной команды.

Эта идея реализована в функции :

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

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

4. C++ Compiler Explorer

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

Компилятор gcc.godbolt.org использует компилятор C++ и выполняет преобразование кода C++, в машинный код, потому это очень удобный инструмент для экспериментов, отладки и обучения.

Иногда лучший способ понять часть кода, это увидеть как она выглядит на уровне железа. Синтаксис высоко двухуровневого языка не может сказать вам о программе все, слишком много моментов и тонкостей скрыто. Вы можете выбрать версию компилятора, с помощью которой хотите собирать программу, например, gcc-6, gcc-5 или clang, Сервис сразу находит ошибки в коде, а также вы можете выбрать стиль отображения машинного кода, например, синтаксис Intel или AT&T.

пример

Различные веб-сайты предоставляют онлайн-доступ к компиляторам C ++. Набор функций онлайн-компилятора значительно варьируется от сайта к сайту, но обычно они позволяют сделать следующее:

  • Вставьте свой код в веб-форму в браузере.
  • Выберите некоторые параметры компилятора и скомпилируйте код.
  • Собирать компилятор и / или выпуск программы.

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

Компиляторы онлайн могут быть полезны для следующих целей:

  • Запустите небольшой фрагмент кода с компьютера, на котором отсутствует компилятор C ++ (смартфоны, планшеты и т. Д.).
  • Убедитесь, что код успешно компилируется с разными компиляторами и работает одинаково, независимо от компилятора, с которым он был скомпилирован.
  • Изучайте или преподавайте основы C ++.
  • Изучите современные возможности C ++ (C ++ 14 и C ++ 17 в ближайшем будущем), когда современный компилятор C ++ недоступен на локальной машине.
  • Найдите ошибку в своем компиляторе по сравнению с большим набором других компиляторов. Проверьте, исправлена ​​ли ошибка компилятора в будущих версиях, которые недоступны на вашем компьютере.
  • Решите проблемы онлайн-судьи.

Какие онлайн-компиляторы не должны использоваться для:

  • Разработка полнофункциональных (даже небольших) приложений с использованием C ++. Обычно онлайн-компиляторы не позволяют связываться со сторонними библиотеками или загружать артефакты сборки.
  • Выполнять интенсивные вычисления. Ресурсы на стороне Sever ограничены, поэтому любая пользовательская программа будет убита через несколько секунд после ее выполнения. Допустимое время выполнения обычно достаточно для тестирования и обучения.
  • Сам сервер компилятора атаки или сторонние хосты в сети.

Примеры:

  • http://codepad.org/ Онлайн-компилятор с совместным использованием кода. Редактирование кода после компиляции с предупреждением или ошибкой исходного кода работает не так хорошо.
  • http://coliru.stacked-crooked.com/ Онлайн-компилятор, для которого вы указываете командную строку. Предоставляет компиляторы GCC и Clang для использования.
  • http://cpp.sh/ — Онлайн-компилятор с поддержкой C ++ 14. Не позволяет редактировать командную строку компилятора, но некоторые параметры доступны через элементы управления графическим интерфейсом.
  • https://gcc.godbolt.org/ — Предоставляет широкий список версий, архитектуры и разборки компилятора. Очень полезно, когда вам нужно проверить, что ваш код компилируется разными компиляторами. GCC, Clang, MSVC ( ), компилятор Intel ( ), ELLCC и Zapcc, причем один или несколько из этих компиляторов доступны для ARM, ARMv8 (как ARM64), Atmel AVR, MIPS, MIPS64, MSP430, PowerPC , x86 и x64 architecutres. Аргументы командной строки компилятора могут быть отредактированы.
  • https://ideone.com/ — Широко используется в сети для иллюстрации поведения фрагмента кода. Предоставляет GCC и Clang для использования, но не позволяет редактировать командную строку компилятора.
  • http://melpon.org/wandbox — Поддерживает многочисленные версии компилятора Clang и GNU / GCC.
  • http://onlinegdb.com/ — крайне минималистичная среда разработки, включающая редактор, компилятор (gcc) и отладчик (gdb).
  • http://rextester.com/ — Предоставляет компиляторы Clang, GCC и Visual Studio для C и C ++ (наряду с компиляторами для других языков), с доступной для использования библиотекой Boost.
  • http://tutorialspoint.com/compile_cpp11_online.php — полнофункциональная оболочка UNIX с GCC и удобный для пользователя проект.
  • http://webcompiler.cloudapp.net/ — Компилятор Online Visual Studio 2015, предоставленный Microsoft в составе RiSE4fun.

Previous
Next

Встроенные функции оболочки

Возможно, вы заметили, что функция вызывает , но выше мы назвали нашу функцию . Это было намеренно! Дело в том, что большинство команд, которые исполняет оболочка, являются программами — но не все. Некоторые из команд встроены прямо в оболочку.

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

Аналогично программа с именем  не сможет выйти из командной оболочки, которая ее вызвала. Эта команда также должна быть встроена в оболочку. Кроме того, большинство оболочек настраиваются с помощью сценариев конфигурации, таких как . Эти сценарии используют команды, которые изменяют работу оболочки. Сами же команды могут изменить работу оболочки, если только они были реализованы внутри самой оболочки.

Соответственно, имеет смысл добавить некоторые команды в оболочку. В эту оболочку мы добавим , и . А вот и реализация этих функций:

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

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

Наконец, идет реализация каждой функции. Функция сначала проверяет наличие своего второго аргумента и выводит сообщение об ошибке, если его нет. Затем она вызывает , проверяет наличие ошибок и завершает работу. Функция справки выводит информативное сообщение и имена всех встроенных функций. А функция выхода возвращает , как сигнал для окончания цикла команд.

1. codepad.io

Codepad — это набор инструментов для компиляции и выполнения программ, которые позволяют работать над кодом совместно. Просто вставьте свой код в редактор Codepad и вы уже можете его скомпилировать и выполнить. Также сервис дает вам ссылку, с помощью которой вы можете поделиться своим кодом с друзьями в чатах или по электронной почте.

Сервис имеет достаточно простой интерфейс, но поддерживает много языков программирования, среди них Си, C++, D, Haskell, Lua, OCaml, PHP, Perl, Plain Text, Python, Ruby и Tcl. Интерфейс не интерактивный, вы набираете программу, затем она отправляется на сервер, компилируется и вы получаете результат выполнения.

Чтение строки

Чтение строки из стандартного потока ввода — это вроде бы просто, но в C это может вызвать много хлопот. Беда в том, что никто не знает заранее, сколько текста пользователь введет в командную оболочку. Нельзя просто выделить блок и надеяться, что пользователи не выйдут за него. Вместо этого нужно перераспределять выделенный блок памяти, если пользователи выйдут за его пределы. Это стандартное решение в C, и именно оно будет использоваться для реализации .

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

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

Те, кто знаком с новыми версиями стандартной библиотеки C, могут заметить, что в есть функция , которая выполняет большую часть работы, реализованной в коде выше. Эта функция была расширением GNU для библиотеки C до 2008 года, а затем была добавлена в спецификацию, поэтому большинство современных Unix-систем уже идут с ней в комплекте.  С  функция становится тривиальной:

HEX и PE-редакторы

Теперь обратная ситуция — бинарник есть, а исходника нет. Как поправить в нем пару байтов? Честно говоря, толкового HEX-редактора в онлайне я в какой-то момент найти не смог и лишь потом случайно наткнулся на него на одном из форумов, где разработчик делился ссылкой на свой текущий проект и интересовался, а стоит ли ему вообще его продолжать. Беглого взгляда на HexPaste (hexpaste.com) было достаточно, чтобы закричать: «Стоит!».

Скажи, вот в каком оффлайн HEX-редакторе есть возможность коллективной работы нескольких людей? А здесь это возможно.

Достаточно поделиться ссылкой на проект (нарпимер, hexpaste.com/WvwX04eV), чтобы к нему мог подключиться кто-то еще. Действует простейшая система контроля версий — каждое значимое изменение необходимо сохранить (закомитить). Интерфейс очень здорово выполнен на AJAX’е, поэтому складывается ощущение, что работаешь в самой обычной, но очень простой программе. Не хватает различных фишек по анализу структуры, в том числе PE-заголовках. Последнее можно исправить с помощью онлайн PE-редактора, который серьезно выручил меня, когда надо было изменить точку входа в exe,шнике.

С помощью proview phpp (pvdasm.reverseengineering.net/PVPHP.php) также можно посмотреть секции, изучить таблицы экспорта/импорта (скажем, для того, чтобы узнать, какие API-функции вызывает утилита) и т.д.

Как командные оболочки запускают процессы

Теперь мы добрались до самой сути того, что делает оболочка. Запуск процессов — это основная функция командных оболочек. Поэтому если вы создаёте оболочку, то должны точно знать, что происходит с процессами и как они запускаются. Именно поэтому сейчас мы поговорим о процессах в Unix.

В Unix есть только два способа запуска процессов. Первый (который не будем брать в счет) — это . Видите ли, когда загружается Unix-система, загружается её ядро. После загрузки и инициализации ядро запускает только один процесс, который называется . Этот процесс выполняется в течение всего времени работы компьютера, и  управляет загрузкой остальных процессов, которые необходимы для его работы.

Поскольку все остальные процессы не , остаётся только один практический способ запуска процессов: системный вызов . Когда эта функция вызывается, операционная система делает дубликат процесса и запускает их параллельно. Первоначальный процесс называется «родительским», а новый — «дочерним». Дочернему процессу  возвращает , а родителю — идентификатор процесса (PID) его дочернего элемента. Таким образом, любой новый процесс можно создать только из копии уже существующего.

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

Благодаря этим двум системным вызовам и возможен запуск большинства программ в Unix. Сперва существующий процесс раздваивается на родительский и дочерний, а затем дочерний процесс использует для замены себя новой программой. Родительский процесс может продолжать делать другие вещи, а также следить за своими дочерними элементами, используя системный вызов .

Да уж, информации немало. Давайте посмотрим на код запуска программы:

Эта функция принимает список аргументов, которые мы создали ранее. Затем она разворачивает процесс и сохраняет возвращаемое значение. Как только возвращает значение, мы получаем два параллельных процесса. Дочернему процессу соответствует первое условие (где ).

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

Если команда возвращает (или любое другое значение), значит, произошла ошибка. Таким образом, мы используем для вывода сообщения об ошибке вместе с именем программы, чтобы было понятно, где произошла ошибка. Затем мы завершаем процесс, но так, чтобы программная оболочка продолжала работать.

Второе условие () проверяет, произошла ли в процессе выполнения  ошибка. Если ошибка есть, мы выводим сообщение об этом на экран, но программа продолжает работать.

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

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Adblock
detector