Форум программистов, компьютерный форум CyberForum.ru

CLI и GUI приложение - в чем разница? - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 13, средняя оценка - 4.62
iRomul
 Аватар для iRomul
158 / 99 / 11
Регистрация: 17.10.2012
Сообщений: 474
Завершенные тесты: 1
12.02.2014, 01:43     CLI и GUI приложение - в чем разница? #1
Доброго времени суток. Недавно задался таким вопросом - в чём разница между типами проектов "Консольное приложение" и "Приложение Win32" в Visual Studio (да и не только в VS, различные типы замечал в других редакторах)? Почему в первом случае создаётся окно консоли, а вот втором - нет? И тогда сразу вдогонку - что такое cout? Почему этот объект работает именно с консолью (в консольном приложении) и как он будет работать с другими типами приложений? И почему если я создам минимальную программу и напишу, например, gcc hello.c -o hello, то программа всё равно запустится в консоли?
Заранее спасибо и прошу прощения за, возможно, глупый вопрос.
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
12.02.2014, 01:43     CLI и GUI приложение - в чем разница?
Посмотрите здесь:

C++ В чем разница.
В чем разница? C++
C++ в чем разница?
C++ В чем разница
C++ Объясните в чем разница
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
12.02.2014, 02:31     CLI и GUI приложение - в чем разница? #2
Цитата Сообщение от iRomul Посмотреть сообщение
в чём разница между типами проектов "Консольное приложение" и "Приложение Win32" в Visual Studio (да и не только в VS, различные типы замечал в других редакторах)?
разница в опциях проекта и соответвенно опциях сборки

Цитата Сообщение от iRomul Посмотреть сообщение
Почему в первом случае создаётся окно консоли, а вот втором - нет?
потому что в опциях компоновки указана подсистема console и windows соответсвенно для каждого типа проекта

Цитата Сообщение от iRomul Посмотреть сообщение
И тогда сразу вдогонку - что такое cout?
объект потока

Цитата Сообщение от iRomul Посмотреть сообщение
Почему этот объект работает именно с консолью (в консольном приложении)
потому что по умолчанию cout привязан к потоку вывода stdout

Цитата Сообщение от iRomul Посмотреть сообщение
и как он будет работать с другими типами приложений?
будет работать как и работал. все приложения имеют поток ввода(stdin), вывода(stdout) и поток для вывода ошибок(stderr)
Ilot
Модератор
Эксперт С++
1767 / 1142 / 223
Регистрация: 16.05.2013
Сообщений: 3,020
Записей в блоге: 5
Завершенные тесты: 1
12.02.2014, 08:48     CLI и GUI приложение - в чем разница? #3
Вот в догонку вырезка из Рихтера. Подробности у него же.
Кликните здесь для просмотра всего текста

Windows поддерживает два типа приложений: основанные на графическом интерфейсе (graphical user interface, GUI) и консольные (console user interface, CUI). У приложений первого типа внешний интерфейс чисто графический. GUI-приложения создают окна, имеют меню, взаимодействуют с пользователем через диалоговые окна и вообще пользуются всей стандартной "Windows'oвской" начинкой. Почти все стандартные программы Windows — Notepad, Calculator, Wordpad и др. — являются GUI-приложениями. Приложения консольного типа работают в текстовом режиме: они не формируют окна, не обрабатывают сообщения и не требуют GUI. И хотя консольные приложения на экране тоже размещаются в окне, в нем содержится только текст. Командные процессоры вроде Cmd.exe (в Windows 2000) или Command.com (в Windows 98) — типичные образцы подобных приложений.

Вместе с тем граница между двумя типами приложений весьма условна. Можно, например, создать консольное приложение, способное отображать диалоговые окна. Скажем, в командном процессоре вполне может быть специальная команда, открывающая графическое диалоговое окно со списком команд, вроде мелочь — а избавляет от запоминания лишней информации. В то же время можно создать и GUI-приложение, выводящее текстовые строки в консольное окно. Я сам часто писал такие пpoграммы: создав консольное окно, я пересылал в него отладочную информацию, связанную с исполняемым приложением. Но, конечно, графический интерфейс предпочтительнее, чем старомодный текстовый. Как показывает опыт, приложения на основе GUI "дружественнее" к пользователю, а значит и более популярны.

Когда Вы создаете проект приложения, Microsoft Visual C++ устанавливает такие ключи для компоновщика, чтобы в исполняемом файле был указан соответствующий тип подсистемы. Для CUI-программ используется ключ /SUBSYSTEM:CONSOLE, а для GUI-приложений — /SUBSYSTEM:WINDOWS. Когда пользователь запускает приложение, загрузчик операционной системы проверяет номер подсистемы, хранящийся в заголовке образа исполняемого файла, и определяет, что это за программа — GUI или СUI. Если номер указывает на приложение последнего типа, загрузчик автоматически создает текстовое консольное окно, а если номер свидетельствует о противоположном — просто загружает программу в память. После того как приложение начинает работать, операционная система больше не интересуется, к какому типу оно относится.

Во всех Windows-приложениях должна быть входная функция за реализацию которой отвечаете Вы. Существует четыре такие функции:

C++
1
2
3
4
5
6
7
int WINAPI WinMain( HINSTANCE hinstExe, HINSTANCE, PSTR pszCmdLine, int nCmdShow);
 
int WINAPI wWinMain( HINSTANCE hinstExe, HINSTANCE, PWSTR pszCmdLine, int nCmdShow);
 
int __cdecl main( int argc, char *argv[], char *envp[]);
 
int _cdecl wmain( int argc, wchar_t *argv[], wchar_t *envp[]);
На самом деле входная функция операционной системой не вызывается. Вместо этого происходит обращение к стартовой функции из библиотеки С/С++. Она инициализирует библиотеку С/С++, чтобы можно было вызывать такие функции, как malloc и free, а также обеспечивает корректное создание любых объявленных Вами глобальных и статических С++-объектов до того, как начнется выполнение Вашего кода. В следующей таблице показано, в каких случаях реализуются те или иные входные функции.
//------------------Тут как бы таблица----------------//
Тип приложения
Входная функция
Стартовая функция, встраиваемая в Ваш исполняемый файл

GUI-приложение, работающее с ANSI-символами и строками
C++
1
2
 WinMain 
 WinMainCRTStartup
GUI-приложение, работающее с Unicode-символами и строками
C++
1
2
 wWinMain 
 wWinMainCRTStartup
CUI-приложение, работающее с ANSI-символами и строками
C++
1
2
 main 
 mainCRTStartup
CUI-приложение, работающее с Unicode-символами и строками
C++
1
2
 wmain 
 wmainCRTStartup
//------------------Тут как бы она заканчивается----------------//

Нужную стартовую функцию в библиотеке С/С++ выбирает компоновщик при сборке исполняемого файла. Если указан ключ /SUBSYSTEM:WINDOWS, компоновщик ищет в Вашем коде функцию WinMain или wWinMain. Если ни одной из них нет, он сообщает об ошибке "unresolved external symbol" ("неразрешенный внешний символ"); в ином случае — выбирает WinMainCRTStartup или wWinMainCRTStartup соответственно.

Аналогичным образом, если задан ключ /SUBSYSTEM:CONSOLE, компоновщик ищет в коде функцию main или wmain и выбирает соответственно mainCRTStartup или wmainCRTStartup; если в коде нет ни main, ни wmain, сообщается о той же ошибке — "unresolved external symbol".

Но не многие знают, что в проекте можно вообще не указывать ключ /SUBSYSTEM компоновщика. Если Вы так и сделаете, компоновщик будет сам определять подсистему для Вашего приложения. При компоновке он проверит, какая из четырех функций (WinMain, wWinMain, main или wmain) присутствует в Вашем коде, и на основании этого выберет подсистему и стартовую функцию из библиотеки С/С++.

Одна из частых ошибок, допускаемых теми, кто лишь начинает работать с Visual С++, — выбор неверного типа проекта. Например, разработчик хочет создать проект Win32 Application, а сам включает в код функцию main. При его сборке он получает сообщение об ошибке, так как для проекта Win32 Application в командной строке компоновщика автоматически указывается ключ /SUBSYSTEM:WlNDOWS, который требует присутствия в коде функции WinMain или wWinMatn. В этот момент раз работчик может выбрать один из четырех вариантов дальнейших действий:

заменить main на WinMain. Как правило, это не лучший вариант, поскольку разработчик скорее всего и хотел создать консольное приложение;
открыть новый проект, на этот раз — Win32 Console Application, и перенести в него все модули кода. Этот вариант весьма утомителен, и возникает ощущение, будто начинаешь все заново;
открыть вкладку Link в диалоговом окне Project Settings и заменить ключ /SUBSYSTEM:WINDOWS на /SUBSYSTEM:CONSOLE. Некоторые думают, что это единственный вариант;
открыть вкладку Link в диалоговом окне Project Settings и вообще убрать ключ /SUBSYSTEM:WINDOWS. Я предпочитаю именно этот способ, потому что он самый гибкий. Компоновщик сам сделает все, что надо, в зависимости от входной функции, которую Вы реализуете в своем коде. Никак не пойму, почему это не предлагается по умолчанию при создании нового проекта Win32 Application или Win32 Console Application.
kravam
12.02.2014, 10:54
  #4

Не по теме:

iRomul, консоль по-моему CUI называется, не?

Jupiter
12.02.2014, 13:38
  #5

Не по теме:

kravam, по трушному command line interface

kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
12.02.2014, 17:00     CLI и GUI приложение - в чем разница? #6
Сообщение было отмечено автором темы, экспертом или модератором как ответ
А, ну ладно. А теперь поделюсь наблюдениями. Может, когда-нибудь ТС вернётся к этой теме.

Значит применительно к наличию консоли, можно и правомерно делить экзешники на две группы- консольные и НЕконсольные. Консольные это те, кто имеют консоль. То есть по запуску она создасться. НЕконсольные это те, кто консоли не имеют. ТО есть по запуску она не создастся. Всё.

GUI тоже неплохо входит в это определение, но именно входит. (Наличие графического интерфейса не является основополагающим для понятийного аппарата, который мы сейчас вводим). Это значит, что консольные приложения МОГУТ иметь графический интерфейс- то самое окно с рюшечками, а могут и не иметь. Также и неконсольные, могут и иметь, а могут и не иметь GUI. Теперь зачем это всё нужно:

1) Консольные без GUI- это то, с чего все начинают программировать. Это пресловутый "hello, word" и прочая. Это мощные и не очень консольные проги- да что далеко ходить, тот же компилятор gcc

2) Консольные с GUI, то есть по работе экзешника создаётся и консоль и GUI. Редко где применяется (инсталлятор MASM). Но я извращенец тот ещё и часто такие проги кропаю вот зачем: я иногда кропаю приложения с GUI (графическим интерфейсом) на ассемблере и их приходится отлаживать. Выводить отладочные надписи в консоль- самое то, вот зачем нужна консоль. Когда приложение сделано и его отлаживать не надо, консоль можно убрать. (Тут важно не путать с консольной программой у которой есть графическая оболочка. Например, архиватор Rar.exe консольный. Но автор решил, что пусть у Rar.exe будет графическая оболочка- и создал экзешник WinRar.exe, который по сути есть графическая оболочка консольного Rar.exe)

3) Неконсольные с GUI- тот же браузер

4) Неконсольные без GUI-это экзешники, у которых нет какого-либо окна- ни графического, ни консоли. Видать, надо так их создателям. Это, конечно вири; всякие служебные программы, коих у тебя работает множество на компе.

//++++++++++++++++++++++++++++++++++++++++++++++

Какой фактор влияет на то, консольное приложение или нет?

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

02- то приложение НЕконсольное
03- то приложение консольное

Вот и всё. А как ты указываешь компилятору- а ну, как сделай мне консольное приложение (то есть сделай в нужном месте 03)? А вот так- ищешь всякие нужные свойства проекта. Джефри Рихтер написал, что можно указывать ключ компиляции /SUBSYSTEM:CONSOLE; Так, а для другого компилятора, коим пользуюсь я (gcc) ключи будут такие:

-mwindows- кропается НЕ консольное приложение. Если этого ключа нет, то кропается консольное приложение.

Но всё эти способы в конечном итоге определяют один байт в экзешнике, каким он будет- 02 или 03 Всё.

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

//++++++++++++++++++++++++++++++++++++++++++++++

Ну и прикола ради ты можешь взять какое-нибудь приложение GUI- тот же браузер и поменять у него значение нужного байта с 3 на 2. После этого приложение станет консольным- в моём понимании, которое я тебе и предлагаю. Поменяешь обратно- консоль при запуске браузера не будет создаваться.

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <windows.H>
#include <stdio.H>
#define NTSIGNATURE(a) ((LPVOID)((BYTE *)a + ((PIMAGE_DOS_HEADER)a)->e_lfanew))
typedef IMAGE_OPTIONAL_HEADER OptionalHeader; 
 
 
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//Эта функция будет находить нам размер файла и его возвращать. 
long int razmer_faila (char* falis_name) {
 
 long int Razmer_Faila;
 HANDLE hFile;
 
 hFile = CreateFile(falis_name,
                       0,
                     FILE_SHARE_READ, 
                     NULL,
                     OPEN_EXISTING, 
                     FILE_ATTRIBUTE_NORMAL, 
                     NULL);
 
 //Проверяем, нормалено файл открыт или нет
 if (hFile== INVALID_HANDLE_VALUE) {
  return 0;
 }
 Razmer_Faila= (long int)GetFileSize(hFile, 0);
 CloseHandle (hFile);
 return Razmer_Faila; 
}
//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
 
 
int main (int agrc, const char* argv[]) {
 SetConsoleCP(1251);
 SetConsoleOutputCP(1251);
                               //+ + +
 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!перегоняем файл в строку!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 char falis_name [MAX_PATH];
 long int Razmer_Faila;
 
 if (agrc!= 3) {
  printf ("Количество аргументов должно быть 2");
  return 1;
 }
 
 //Первое, что сделааем, это введём имя файла, который будем перегонять в строку:
 strcpy (falis_name, argv[1]);
 
 
 //Теперь находим размер файла
 if (!(Razmer_Faila= razmer_faila (falis_name))) {
  printf ("не получилось найти размер экзешника\n");
  return 1;
 }
 
 
 //Теперь открываем файл на чтение
 FILE* f;
 if (!(f= fopen (falis_name, "rb"))) {
  printf ("экзешник на чтение не открыт\n");
  return 1; 
 }  
 
 //Теперь переписываем файл в строку нужного размера. ДЛя этого такую строку надо выделить
 //unsigned char* stroka_dla_faila= new unsigned char [Razmer_Faila+ 1]; 
 unsigned char* stroka_dla_faila= new unsigned char [Razmer_Faila]; 
 
 
 //И собсно запись файла в эту строку
 if (fread (stroka_dla_faila, 1, Razmer_Faila, f)<Razmer_Faila) {
  printf ("не удалось считать экзешник в строку\n");
  return 1;
 }
 
 fclose (f);
 
 
 //Потом не забыть вернуть память оси с помощью delete 
 //!!!!!!!!!!!!!!!!!!!!!!!!!!!!конец перегоняем файл в строку!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 
 PIMAGE_NT_HEADERS pPE=(PIMAGE_NT_HEADERS)NTSIGNATURE((long)stroka_dla_faila);
 
 if (!(strcmp(argv[2], "y")))
  pPE->OptionalHeader.Subsystem= 3;
 else 
  if (!(strcmp(argv[2], "n")))
   pPE->OptionalHeader.Subsystem= 2;
  else {
   printf ("Вторым параметром должно быть 'y' или 'n'\n");
   return 1;
  }
 
 
 
 //Перегоним строку в файл
 if (!(f= fopen (falis_name, "wb"))) {
  printf ("файл на запись не открыт\n");
  return 0; 
 }  
 
 fwrite (stroka_dla_faila, 1, Razmer_Faila, f); 
 delete [] stroka_dla_faila;
 fclose (f);
 return 0;
}
работать так: бросаешь в одну папку с ra.exe файл firefox.exe (это браузер, можешь что-нибудь другое) и командуешь
Bash
1
ra.exe firefox.exe y
Теперь по запуску firefox.exe увидишь консоль, только не забудь, прежде чем ткнуть на него вернуть его в прежнюю директорию. Не захочешь консоль, командуй

Bash
1
ra.exe firefox.exe n
И всё, firefox.exe снова стал неконсольным приложением, каким и был.
iRomul
 Аватар для iRomul
158 / 99 / 11
Регистрация: 17.10.2012
Сообщений: 474
Завершенные тесты: 1
12.02.2014, 19:17  [ТС]     CLI и GUI приложение - в чем разница? #7
Спасибо всем большое за ответы! Всё просто оказалось. Но получается, что стандартный поток в любом случае сохраняется? Т.е. если я запущу программу, у которой в заголовке в нужном байте стоит 02, но в теле программы вызывается printf и я всё равно запущу программу через консоль - увижу ли я там результат работы printf?
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
12.02.2014, 19:32     CLI и GUI приложение - в чем разница? #8
Так ты ничему не научишься. Создай НЕконсольное приложение любым известным тебе способом

C++
1
2
3
4
5
6
#include <stdio.h>
int main () {
 printf ("Hello, word!\n");
 getchar ();
 return 0;
}
Ну или с похожим кодом. И запусти в консоли.
Kastaneda
Модератор
Эксперт С++
 Аватар для Kastaneda
4237 / 2770 / 218
Регистрация: 12.12.2009
Сообщений: 7,104
Записей в блоге: 1
Завершенные тесты: 1
12.02.2014, 19:36     CLI и GUI приложение - в чем разница? #9
Цитата Сообщение от iRomul Посмотреть сообщение
что такое cout? Почему этот объект работает именно с консолью
потому что cout - это console out
iRomul
 Аватар для iRomul
158 / 99 / 11
Регистрация: 17.10.2012
Сообщений: 474
Завершенные тесты: 1
12.02.2014, 19:38  [ТС]     CLI и GUI приложение - в чем разница? #10
Цитата Сообщение от kravam Посмотреть сообщение
Так ты ничему не научишься.
Соглашусь.
Но в консоль ничего не вывелось (GCC).
alsav22
5282 / 4801 / 442
Регистрация: 04.06.2011
Сообщений: 13,587
12.02.2014, 19:42     CLI и GUI приложение - в чем разница? #11
Цитата Сообщение от Kastaneda Посмотреть сообщение
потому что cout - это console out
Тоже так думал. Однако(Бьерн Страуструп - Программирование. Принципы и практика использования C++):
Миниатюры
CLI и GUI приложение - в чем разница?  
kravam
быдлокодер
 Аватар для kravam
1512 / 872 / 44
Регистрация: 04.06.2008
Сообщений: 5,271
12.02.2014, 19:42     CLI и GUI приложение - в чем разница? #12
Цитата Сообщение от iRomul Посмотреть сообщение
Соглашусь.
Но в консоль ничего не вывелось (GCC).
Вот ты и ответил на свой вопрос. У меня тоже кстати, ничего не вывелось.
Kastaneda
12.02.2014, 19:52
  #13

Не по теме:

Цитата Сообщение от alsav22 Посмотреть сообщение
Тоже так думал.
alsav22, спасибо, не знал. Про console out прочитал в какой-то книги для начинающих будучи начинающим и с тех пор не пытался выяснить, что это значит.

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
12.02.2014, 21:55     CLI и GUI приложение - в чем разница?
Еще ссылки по теме:

В чем разница C++
C++ В чем разница?
C++ Как запустить GUI приложение (например, notepad.exe) без отображения GUI?

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

Или воспользуйтесь поиском по форуму:
Jupiter
Каратель
Эксперт C++
6543 / 3963 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
12.02.2014, 21:55     CLI и GUI приложение - в чем разница? #14
Цитата Сообщение от kravam Посмотреть сообщение
У меня тоже кстати, ничего не вывелось.
и не должно
Yandex
Объявления
12.02.2014, 21:55     CLI и GUI приложение - в чем разница?
Ответ Создать тему

Метки
cli, gui
Опции темы

Текущее время: 16:31. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru