Как сохранить консольное приложение c
Алгоритм работы при создании C++-проекта в Visual Studio
1. New Project: Создание проекта.
- Пункт меню File -> New -> Project (Файл -> Создать -> Проект).
- В открывшемся окне в разделе Project Types (Установленные) найти Visual C++.
- В разделе Templates (Шаблоны) выбрать Win32 Console Application (Консольное приложение Win32).
- Указать имя нового «решения» (Solution Name) и имя проекта (Name).
- Сохранить проект на локальном диске в легко доступном месте (например, D:\Projects).
- Можно снять галочку Create folder for solution (Создать каталог для решения), чтобы не множить каталоги без необходимости.
- В следующем диалоговом окне щелкнуть Далее и затем выбрать Application Settings (Дополнительные параметры) -> Empty Project (Пустой проект). Убрать галочку с пункта Проверки жизненного цикла…
2. Add files: Добавление файлов.
Правый клик на проекте в окне Solution Explorer (Обозреватель решений) — пункт Add (Добавить) — пункт Create New Item (Создать элемент) или Add existing Item (Существующий элемент). Для этого и любого другого проекта понадобится как минимум один файл с точкой входа в программу — функцией main.
3. Exclude files: Исключение файлов.
Сначала удобно создать один проект и добавлять в него по одному файлу с решением каждой отдельной задачи. Однако при этом возникает проблема: в нескольких файлах проекта присутствует функция main, что противоречит правилам C++. Для решения данной проблемы, необходимо «исключать» файлы из проекта (правый клик на файле, Exclude from project (Исключить)). При этом файлы исчезнут из окна проекта, однако сохранятся в каталоге проекта на диске.
Обходной путь, который я использую, пока не нахожу более чистого подхода, - создать подкласс TextWriter , переопределив методы записи, чтобы они оба записывали в файл и вызывали исходный писатель stdout. Что-то вроде этого:
Убедитесь, что он все время записывает и сбрасывает файл. Я бы хотел сделать это только в конце выполнения, но я не мог найти никакого доступа к выходному буферу.
Также извините за неточности в приведенном выше коде (пришлось написать его ad hoc , извините;).
Идеальным решением для этого является использование log4net с консольным приложением и файловым приложением. Также доступно множество других приложений. Это также позволяет вам включать и выключать различные приложения во время выполнения.
Замечательная идея! Мне действительно нужен регистратор. Таким образом, я могу хранить гораздо больше информации, чем просто показано пользователю (и меньше его беспокоить). Часто лучшее решение исходит из другого подхода, исходящего от кого-то постороннего по отношению к проблеме. Я думаю, что в этом случае было бы излишним использовать стороннюю библиотеку, когда для добавления необходимой функциональности в систему может потребоваться лишь небольшой объем работы. Я согласен, что log4net - это довольно тяжелая зависимость. Это больше похоже на взлом, чем на подход, изложенный в вопросе. Хороший момент. Я проверю эту стоимость, когда вернусь к работе на этой неделе. Основное преимущество, которое я здесь обнаружил, заключается в том, что легче сохранить отладочную информацию в файле, не выводя ее на экран. Кроме того, последовательный ввод-вывод является основным узким местом в моем проекте.Я не думаю, что в вашем подходе что-то не так.
Если вам нужен код многократного использования, рассмотрите возможность реализации класса с именем MultiWriter или чего-нибудь подобного, который принимает в качестве входных данных два (или N?) TextWriter потока и распределяет все записи, сбросы и т. Д. В эти потоки. Затем вы можете сделать этот файл / консоль, но так же легко вы можете разделить любой выходной поток. Полезный!
Проблема с моим подходом в том, что я держу файл открытым и все время его промываю. И, я полагаю, открытие и закрытие файла при каждой записи было бы обременительным. Однако ваша идея MultiWriter очень умная :)Создайте "выходной" класс, который может иметь разные классы, привязанные к интерфейсу вывода текста. Вы сообщаете выходному классу, он автоматически отправляет выходные данные добавленным вами классам (ConsoleOutput, TextFileOutput, WhateverOutput) .. И так далее .. Это также оставляет вас открытыми для добавления других типов «выходных» (таких как xml / xslt, чтобы получить отчет в красивом формате?).
Ознакомьтесь с коллекцией прослушивателей трассировки, чтобы понять, что я имею в виду.
Рассмотрите возможность рефакторинга вашего приложения, чтобы отделить части взаимодействия с пользователем от бизнес-логики. По моему опыту, такое разделение весьма полезно для структуры вашей программы.
Для конкретной проблемы, которую вы здесь пытаетесь решить, для части взаимодействия с пользователем становится просто изменить свое поведение с Console.WriteLine на файловый ввод-вывод.
Я работаю над реализацией аналогичной функции для захвата вывода, отправляемого в консоль, и сохранения его в журнале, при этом передавая вывод в реальном времени в обычную консоль, чтобы он не нарушал работу приложения (например, если это консольное приложение !).
Если вы все еще пытаетесь сделать это в своем собственном коде, сохраняя вывод консоли (в отличие от использования системы журналов для сохранения только той информации, которая вам действительно важна), я думаю, вы можете избежать сброса после каждой записи, пока поскольку вы также переопределяете Flush () и убедитесь, что он сбрасывает исходный stdoutWriter , который вы сохранили, а также ваш fileWriter . Вы хотите сделать это в случае, если приложение пытается сбросить частичную строку на консоль для немедленного отображения (например, приглашения ввода, индикатора выполнения и т. Д.), Чтобы переопределить обычную буферизацию строки.
Если при таком подходе возникают проблемы с слишком долгой буферизацией вывода на консоль, вам может потребоваться убедиться, что WriteLine () сбрасывает stdoutWriter (но, вероятно, не нужно сбрасывать fileWriter , за исключением случаев, когда ваш Flush () называется переопределение). Но я бы подумал, что исходный Console.Out (фактически идущий в консоль) автоматически сбрасывает свой буфер при переходе на новую строку, так что вам не нужно форсировать его.
Вы также можете переопределить Close (), чтобы (очистить и) закрыть свой fileWriter (и, возможно, stdoutWriter ), но я не уверен, действительно ли это нужно или Close () в базовый TextWriter вызовет Flush () (который вы уже переопределите), и вы можете полагаться на выход приложения, чтобы закрыть свой файл. Вы, вероятно, должны проверить, что он сбрасывается при выходе, чтобы быть уверенным. И имейте в виду, что аварийный выход (сбой), скорее всего, не очистит буферизованный вывод. Если это проблема, может быть желательно сбросить fileWriter при переводе строки, но это еще одна хитрая банка червей, которую нужно решить.
Самой очевидной причиной является отсутствие Visual Studio 2010 или какой-то другой графической IDE-среды.
Работа может выполняться в университете, где использование инструментов для генерации кода и IDE-сред обычно запрещено.
Планируется применение автоматизированных средств разработки, таких как msbuild.exe, которые требуют знать опции командной строки для используемых инструментов.
Указание целевых входных и выходных параметров
Первым делом важно разобраться с тем, как указывать имя и тип создаваемой сборки (т.е., например, консольное приложение по имени MyShell.exe, библиотека кода по имени MathLib.dll или приложение Windows Presentation Foundation по имени Halo8.ехе). Каждый из возможных вариантов имеет соответствующий флаг, который нужно передать компилятору csc.ехе в виде параметра командной строки.
Обратите внимание, что параметры, передаваемые компилятору командной строки (а также большинству других утилит командной строки), могут сопровождаться префиксом в виде символа дефиса (-) или слеша (/).
Параметр | Описание |
---|---|
/out | Этот параметр применяется для указания имени создаваемой сборки. По умолчанию сборке присваивается то же имя, что у входного файла *.сs |
/target:exe | Этот параметр позволяет создавать исполняемое консольное приложение. Сборка такого типа генерируется по умолчанию, потому при создании подобного приложения данный параметр можно опускать |
/target:library | Этот параметр позволяет создавать однофайловую сборку *.dll |
/target:module | Этот параметр позволяет создавать модуль. Модули являются элементами многофайловых сборок |
/target:winexe | Хотя приложения с графическим пользовательским интерфейсом можно создавать с применением параметра /target: ехе, параметр /target: winexe позволяет предотвратить открытие окна консоли под остальными окнами |
Чтобы скомпилировать TestApplication.cs в консольное приложение TestApplication.exe, перейдите в каталог, в котором был сохранен файл исходного кода (с помощью флага cd) и введите следующую команду:
Теперь можно попробовать запустить приложение TestApplication.ехе из командной строки, введя имя его исполняемого файла:
Добавление ссылок на внешние сборки
Далее в командной строке нужно проинформировать компилятор csc.exe о том, в какой сборке содержатся используемые пространства имен. Поскольку применялся класс MessageBox из пространства имен System.Windows.Forms, значит, нужно указать компилятору на сборку System.Windows.Forms.dll, что делается с помощью флага /reference (или его сокращенной версии /r):
Кстати, как поступить, когда необходимо указать csc.exe несколько внешних сборок? Для этого нужно просто перечислить все сборки через точку с запятой. В рассматриваемом примере ссылаться на несколько сборок не требуется, но ниже приведена команда, которая иллюстрирует перечисление множества сборок:
csc /r:System.Windows.Forms.dll;System.Drawing.dll *.cs
Компиляция нескольких файлов исходного кода
Изменим исходный класс TestApplication так, чтобы в нем использовался класс этого нового типа:
Вывод, получаемый после запуска этой программы, идентичен предыдущей программе. Единственное отличие между этими двумя приложениями связано с разнесением логики по нескольким файлам.
В случае необходимости допускается также указывать и несколько ответных *.rsp файлов в качестве входных параметров (например, csc @FirstFile.rsp @SecondFile.rsp @ThirdFile.rsp). При таком подходе, однако, следует иметь в виду, что компилятор обрабатывает параметры команд по мере их поступления. Следовательно, аргументы командной строки, содержащиеся в поступающем позже файле *.rsp, могут переопределять параметры из предыдущего ответного файла.
Стоит отметить, что в случае добавления с помощью опции /r ссылок на сборки, которые на самом деле не используются, компилятор их проигнорирует. Поэтому беспокоиться по поводу "разбухания кода" не нужно.
Перед написанием нашей первой программы мы еще должны кое-что узнать.
Теория
Во-первых, несмотря на то, что код ваших программ находится в файлах .cpp, эти файлы добавляются в проект. Проект содержит все необходимые файлы вашей программы, а также сохраняет указанные вами настройки вашей IDE. Каждый раз, при открытии проекта, он запускается с того момента, на котором вы остановились в прошлый раз. При компиляции программы, проект говорит компилятору и линкеру, какие файлы нужно скомпилировать, а какие связать. Стоит отметить, что файлы проекта одной IDE не будут работать в другой IDE. Вам придется создать новый проект (в другой IDE).
В-третьих, при создании нового проекта большинство IDE автоматически добавят ваш проект в рабочее пространство. Рабочее пространство — это своеобразный контейнер, который может содержать один или несколько связанных проектов. Несмотря на то, что вы можете добавить несколько проектов в одно рабочее пространство, все же рекомендуется создавать отдельное рабочее пространство для каждой программы. Это намного упрощает работу для новичков.
Традиционно, первой программой на новом языке программирования является всеми известная программа «Hello, world!». Мы не будем нарушать традиции 🙂
Пользователям Visual Studio
Для создания нового проекта в Visual Studio 2019, вам нужно сначала запустить эту IDE, затем выбрать "Файл" > "Создать" > "Проект" :
Дальше появится диалоговое окно, где вам нужно будет выбрать "Консольное приложение Windows" из вкладки "Visual C++" и нажать "ОК" :
Также вы можете указать имя проекта (любое) и его расположение (рекомендую ничего не менять) в соответствующих полях.
В текстовом редакторе вы увидите, что уже есть некоторый текст и код — удалите его, а затем напечатайте или скопируйте следующий код:
Читайте также: