Программа C отлично выводит на стандартный вывод в Linux, но ничего не выводит в Windows

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

Программы прекрасно работают в Linux. Он работает исключительно через стандартный ввод и вывод. Я фаззил их, используя случайные файлы размером 1 ГиБ. Однако когда я пытаюсь скомпилировать его для Windows (используя cl.exe или x86_64-w64-mingw32-gcc (в WSL), программы отказываются выводить что-либо в любой выходной поток.

Я пытался удалить все выходные данные в stderr, пытался выполнить два вызова putchar() с помощью '\r''\n' (думая, что это проблема с LF и CRLF), fflush() каждый раз, когда я putchar(), но это все равно не сработает. Единственное, что сработало, — это полностью закомментировать основной while цикл программы-кодировщика, в котором мне удалось получить исходную напечатанную строку FILE:.

Поскольку цикл не закомментирован, я даже не получу первый printf() с немедленным fflush(stdout) после него. Однако программа будет остановлена. Ниже представлена ​​одна из программ, которую я хочу отладить в первую очередь.

Для проверки работоспособности я попытался скомпилировать простую программу Hello World!, которая использует и printf(), и putchar(), и она отлично работает в Windows, но моя конкретная программа - нет. Я в растерянности, где проверить в первую очередь.

js8file_enc.c

#include "js8file_enc.h"

// From stdin
bool fill_buffer(bool * bitbuf, size_t * buf_size, bool ** bitbuf_read_head_ptr){
    // Justify remaining buffer back to the beginning
    if (*buf_size > 0){
        memmove(bitbuf, *bitbuf_read_head_ptr, *buf_size);
    }
    // Read from stdin (indeterminate length), keep track of buffer size
    char buf[BUF_SIZE];
    // The max bytes here is sizeof(buf) - ceil(*buf_size/8) expressed in a roundabout way.
    // This will fill our byte buffer as much as possible for the bit buffer to be near-full in the next step.
    size_t increase = fread(buf, 1, sizeof(buf) - ((*buf_size+8-1)/8), stdin);
    // Extract bits from byte buffer
    for(size_t i = 0; i < increase; i++){
        for(int j = 0; j < 8; j++){
            bitbuf[*buf_size] = (buf[i] >> (7 - j)) & 1;
            (*buf_size)++;
        }
    }
    *bitbuf_read_head_ptr = bitbuf;
    return increase > 0;
}

int main(){
    printf("FILE:");
    bool bitbuf[BUF_SIZE*8];
    bool * bitbuf_read_head = bitbuf;
    size_t buf_size = 0; // In bits
    while(true){
        if (buf_size < 8){ // 8 bits, length of longest key
            if (!fill_buffer(bitbuf, &buf_size, &bitbuf_read_head)){
                // There may still be bits remaining (<8), encode the rest
                while(buf_size > 0){
                    for(int i = buf_size; i > 0; i--){
                        if (LUT[i] == NULL){
                            continue;
                        }
                        uint8_t key = 0;
                        for(int j = 0; j < i; j++){
                            key |= bitbuf_read_head[j] << (i - j - 1);
                        }
                        if (LUT[i][key] != 0){
                            putchar(LUT[i][key]);
                            bitbuf_read_head += i;
                            buf_size -= i;
                            break;
                        }
                    }
                }
                break;
            }
        }
        int max_key_size = (buf_size < 8) ? buf_size : 8;
        // Produce keys in descending order, check for first match, write to stdout, then move buffer head.
        // If there are no codewords of length n (that is, LUT[n] is NULL), then we skip to the next length.
        for(int i = max_key_size; i > 0; i--){
            if (LUT[i] == NULL){
                continue;
            }
            uint8_t key = 0;
            for(int j = 0; j < i; j++){
                key |= bitbuf_read_head[j] << (i - j - 1);
            }
            if (LUT[i][key] != 0){
                putchar(LUT[i][key]);
                bitbuf_read_head += i;
                buf_size -= i;
                break;
            }
        }
    }
    fflush(stdout);
    fprintf(stderr, "<EOF>\n");
    fflush(stderr);
    return 0;
}

js8file_enc.h

#include "ref.h"

// Indexed by codeword length (.bits)
const unsigned char * LUT[9] = {
    [0] = NULL,
    [1] = (unsigned char[0b10]){
        [0b0] = ' ',
        [0b1] = 'E'
    },
    [2] = NULL,
    [3] = NULL,
    [4] = (unsigned char[0b10000]){
        [0b1101] = 'T',
        [0b0011] = 'A'
    },
    [5] = (unsigned char[0b100000]){
        [0b11111] = 'O',
        [0b11100] = 'I',
        [0b10111] = 'N',
        [0b10100] = 'S',
        [0b00011] = 'H',
        [0b00000] = 'R'
    },
    [6] = (unsigned char[0b1000000]){
        [0b111011] = 'D',
        [0b110011] = 'L',
        [0b110001] = 'C',
        [0b101101] = 'U',
        [0b101011] = 'M',
        [0b001011] = 'W',
        [0b001001] = 'F',
        [0b000101] = 'G',
        [0b000011] = 'Y'
    },
    [7] = (unsigned char[0b10000000]){
        [0b1111011] = 'P',
        [0b1111001] = 'B',
        [0b1110100] = '.',
        [0b1100101] = 'V',
        [0b1100100] = 'K',
        [0b1100001] = '-',
        [0b1100000] = '+',
        [0b1011001] = '?',
        [0b1011000] = '!',
        [0b1010101] = '"',
        [0b1010100] = 'X',
        [0b0010101] = '0',
        [0b0010100] = 'J',
        [0b0010001] = '1',
        [0b0010000] = 'Q',
        [0b0001001] = '2',
        [0b0001000] = 'Z',
        [0b0000101] = '3',
        [0b0000100] = '5'
    },
    [8] = (unsigned char[0b100000000]){
        [0b11110101] = '4',
        [0b11110100] = '9',
        [0b11110001] = '8',
        [0b11110000] = '6',
        [0b11101011] = '7',
        [0b11101010] = '/'
    }
};

ссылка.h

#include <stdio.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <sys/types.h>
// DEFAULT SETTING: 524288
// 512 KiB, packed (bytes read from stdin)
// 4 MiB, unpacked (512 KiB worth of bits stored in bitbuf)
// Changed for debugging purposes
#define BUF_SIZE 524288

typedef const struct codeword{
    const uint8_t key;
    const uint8_t bits;
} codeword;

Обновлено: В первом ответе говорится, что размер стека Windows по умолчанию составляет 1 МБ. Я этого не знал, и я проверю это исправление.

🤔 А знаете ли вы, что...
C оставался популярным и актуальным языком программирования на протяжении многих десятилетий.


51
1

Ответ:

Решено

Эта строка в main():

bool bitbuf[BUF_SIZE * 8];

Где BUF_SIZE определяется в ref.h как 524288. При запуске из стека будет выделено 4 мегабайта. Это приведет к сбою вашей программы еще до того, как она доберется до оператора printf("FILE:").

По умолчанию компилятор VC допускает размер стека только 1 МБ.

Решения:

  • Измените приведенную выше строку следующим образом:

    bool* bitbuf = malloc(BUF_SIZE*8);

    (Не забудьте поставить free, когда закончите)

ИЛИ

  • Используйте флаги компилятора и компоновщика для увеличения размера стека (я могу поискать это, если хотите), но приведенное выше решение с использованием динамического распределения памяти лучше.

Аналогично, char buf[BUF_SIZE]; в fill_buffer занимает 512 КБ стека.