#c #windows #console #mingw #msys2
#c #Windows #консоль #mingw #msys2
Вопрос:
Если я скомпилирую этот исходный код:
#include <stdio.h>
int main(int argc, char* args[]) {
printf("Done!n");
return 0;
}
с gcc hello.c -o hello -mwindows
помощью msys2 с помощью mingw-w64-x86_64-toolchain
toolchain, а затем запустите его изнутри msys2, я увижу:
В то же время, если я вызову этот же исполняемый файл из powershell (или cmd), я увижу:
Честно говоря, учитывая -mwindows
, что говорится о создании исполняемого файла Windows в отличие от консольного, я не удивлен последним — я видел это много раз.
Но как msys2 удается отображать этот вывод?
Ответ №1:
Существует очень мало различий между консольным и графическим приложением в Windows, и код stdio во время выполнения C обычно не волнует, он заботится только о стандартных дескрипторах Win32.
Основное отличие заключается в том, как CreateProcess
работает родительское приложение.
-
Консольное приложение подключается к стандартным дескрипторам Win32 родителей, если у родителя есть консоль. Если у родительского устройства нет консоли, для приложения создается новое окно консоли. Родительский элемент может передавать необязательные флаги
CreateProcess
, чтобы принудительно / запретить новую консоль. -
Приложение с графическим интерфейсом не подключено к стандартным дескрипторам Win32, и новая консоль не создается.
Powershell.exe это настоящее консольное приложение, и оно может использовать CreateProcess
обработку по умолчанию. Поскольку ваше приложение не является консольным приложением, оно будет создано без стандартных дескрипторов, и поэтому ему некуда записывать.
Приложение терминала msys2, вероятно, не является настоящим консольным приложением и, вероятно, вызывает CreateProcess
принудительные дескрипторы ( STARTF_USESTDHANDLES
). Эти дескрипторы, вероятно, являются дескрипторами каналов. Ваше приложение будет видеть эти дескрипторы как перенаправленные дескрипторы stdio и выполняться аналогично тому, как cmd.exe выступал yourconsoleapp.exe | otherconsoleapp.exe
бы .
Комментарии:
1. Да, MSYS2 использует именованные каналы для стандартного ввода-вывода. Это обычная проблема для консольных приложений, которые используют полную буферизацию при записи в файл канала или диска, с обходными путями, такими как winpty.
2. Что касается CMD, интересно, что он временно изменяет свои собственные стандартные дескрипторы и полагается на наследование, а не на использование
STARTUPINFO
стандартных дескрипторов. Сначала он пытается вызватьCreateProcessW
сbInheritHandles
помощью asTRUE
. Если это удается, дочерний элемент создается с копией значений стандартных дескрипторов родителей, независимо от того, унаследованы они или нет. ВнутреннийConsoleHandle
не наследуется для неконсольного приложения, но наследуемые стандартные дескрипторы ввода-вывода наследуются во всех случаях, поэтому мы можем сделать что-то вроде.hello.exe | more
, учитывая «hello.exe » это неконсольная сборка операционной системы.3. Если вместо этого мы запускаем ассоциацию file by filetype, CMD использует
ShellExecuteExW
, и в этом случае результат зависит от того, является ли связанный исполняемый файл консольным приложением.ShellExecuteExW
не наследует дескрипторы, поэтомуfile.ext | more
не будет работать, если «.EXT» связан с нашим неконсольным «hello.exe «. Если мы создадим «hello.exe «как консольное приложение, оно будет работать, потомуNtCreateUserProcess
что неявно дублирует (а не наследует) стандартные дескрипторы консольного приложения.