Портативный способ положить стандартный вывод в двоичном режиме
Я пишу программы на C, используемые как cgi, которые генерируют и выводят gif-изображения. Они используются на HTML-страницах с тегами вида<img src="/cgi-bin/gifprogram.cgi?param=val&etc">
где параметры строки запроса описывают изображение, которое будет сгенерировано cgi.
CG-программы, вызываемые следующим образом, отправляют свой вывод на стандартный вывод. И в этом случае вывод представляет собой изображение в формате gif, содержащее множество двоичных (непечатных) байтов. Это уже отлично работает на Unix / Linux. Но Windows, по-видимому, требует отдельного непереносимого_setmode(_fileno(stdout),_O_BINARY)
вызов (и некоторые специфичные для Windows#include
«S). В противном случае вы получите обычную проблему cr / lf, то есть каждому 0x0A предшествует ложный 0x0D. И это не выглядит хорошо в GIF :(
Есть ли какой-либо переносимый способ обойти эту проблему, используя стандарт C ANSI без какого-либо специфичного для платформы синтаксиса и без большого количества#ifdef
что попытаться обнаружить среду компиляции Windows? Более того, некоторые компиляторы Windows, очевидно, используют_setmode(_fileno(stdout),_O_BINARY)
в то время как другие используютsetmode(fileno(stdout),O_BINARY)
, который я также должен попытаться обнаружить.
>> << Редактировать В ответ на комментарии ...
Спасибо, парни. По-видимому, мне придется взять некоторые иначе полностью совместимые с posix / переносимые программы, и бездельничать с ними только для окон [nb, JoNaThAn: действительно, не нужно редактировать, чтобы использовать это заглавные буквы :), - мой личный стиль написания намеренно грамматически свободный.
Ниже приведено первое описание некоторых глупостей, которые я собираюсь представить. Кажется, работает, насколько я могу судить, используя Mingw. Достаточно ли, т. Е. Работает для всех или большинства других компиляторов? И нужен ли, т. Е. Какой-нибудь короткий и аккуратный / быстрый и грязный способ сделать то же самое с меньшим количеством / более читаемых строк кода?
/* ---
* windows-specific header info
* ---------------------------- */
#ifndef WINDOWS /* -DWINDOWS not supplied by user */
#if defined(_WINDOWS) || defined(_WIN32) || defined(WIN32) \
|| defined(DJGPP) /* try to recognize windows compilers */ \
|| defined(_USRDLL) /* must be WINDOWS if compiling for DLL */
#define WINDOWS /* signal windows */
#endif
#endif
#ifdef WINDOWS /* Windows opens stdout in char mode, and */
#include <fcntl.h> /* precedes every 0x0A with spurious 0x0D.*/
#include <io.h> /* So emitcache() issues a Win _setmode() */
/* call to put stdout in binary mode. */
#if defined(_O_BINARY) && !defined(O_BINARY) /* only have _O_BINARY */
#define O_BINARY _O_BINARY /* make O_BINARY available, etc... */
#define setmode _setmode
#define fileno _fileno
#endif
#if defined(_O_BINARY) || defined(O_BINARY) /* setmode() now available */
#define HAVE_SETMODE /* so we'll use setmode() */
#endif
#if defined(_MSC_VER) && defined(_DEBUG) /* MS VC++ in debug mode */
/* to show source file and line numbers where memory leaks occur... */
#define _CRTDBG_MAP_ALLOC /* ...include this debug macro */
#include <crtdbg.h> /* and this debug library */
#endif
#define ISWINDOWS 1
#else
#define ISWINDOWS 0
#endif
И следующий соответствующий код, чтобы убедиться, что стандартный вывод находится в двоичном режиме
#if ISWINDOWS /* compiling for win... */
#ifdef HAVE_SETMODE /* try to use setmode()*/
if ( setmode ( fileno (stdout), O_BINARY) /* to set stdout */
== -1 ) /* handle error here*/ ; /* to binary mode */
#else /* setmode not available */
#if 1 /* so try this...*/
freopen ("CON", "wb", stdout); /* freopen stdout binary */
#else /* or maybe this... */
stdout = fdopen (STDOUT_FILENO, "wb"); /*fdopen stdout binary*/
#endif /* done */
#endif /* " */
#endif /* " */
Вы заметите, что я пытаюсь предложить альтернативы setmode (). Хотя мое альтернативное тестирование не было успешным, я оставил синтаксис для дальнейшего использования, на случай, если некоторые из них в конечном итоге окажутся полезными.