У меня есть код с целью чтения двоичного файла с использованием fread, а затем обработки данных и отправки их в char *buffer размером 1310720
На данный момент (с моим рабочим кодом) я считывал файл побайтно для выполнения некоторой обработки, а затем записывал байт 1 на 1 в unsigned char array[i]
Я использовал что-то вроде этого
void read_input_file(FILE *stream,char *buffer)
{
long i = 0;
unsigned char tmp_buf[1310720] ;
unsigned char *calc = malloc(1);
while(i < 1310720)
{
fread(calc,1,1,stream);
tmp_buf[i] = round(*calc /128);//this is an example
i++;
}
memcpy(buffer, &tmp_buf[0], 1310720);
}
это работало, но теперь я хочу (по соображениям производительности) прочитать фрагмент данных, размер которого равен размеру буфера. Итак, я попытался использовать что-то вроде этого:
void read_input_file(FILE *stream,char *buffer)
{
long i = 0;
unsigned char tmp_buf[1310720] ;
unsigned char *calc = malloc(1310720);
fread(calc,1310720,1,stream);
while(i < 1310720)
{
tmp_buf[i] = round(calc[i] /128);//this is an example
i++;
}
memcpy(buffer, &tmp_buf[0], 1310720);
}
но что бы я ни делал, я получил ошибку выполнения, когда программа вылетает. Я пробовал много разных вещей и кодов, но ничего не работает.
Итак, как мне прочитать большой кусок данных в буфер, а затем получить к нему доступ побайтно для обработки данных?
Вопросы, требующие помощи в отладке, как правило, должны предоставлять минимальный воспроизводимый пример проблемы, который включает функцию main
и все #include
директивы. Это позволяет другим людям легко тестировать вашу программу, просто используя копирование и вставку.
Вы на винде? Ограничение размера стека в Windows составляет 1024 КБ (1 МБ), и вы пытаетесь создать в стеке буфер размером 1280 КБ. Используйте динамическое выделение памяти дважды. Даже в Unix-подобных системах ограничение размера стека обычно составляет 8 МБ, поэтому выделение такого большого массива в стеке немного сомнительно.
Вы также теряете память в показанном коде — вы не освобождаете calc
перед возвратом. Я предполагаю, что отсутствие проверки ошибок связано с упрощением кода для SO, но не пропускайте проверку ошибок (на malloc()
и fread()
) в вашем реальном коде. И зачем использовать промежуточный буфер? Почему бы просто не скопировать обработанные данные байт за байтом в выходной буфер? Одной из причин может быть «целостность транзакций». Если что-то пойдет не так, вы вообще не захотите изменять buffer
. Тогда промежуточный результат является разумным. Вы также должны передать размер буфера в качестве параметра функции для проверки.
в чем смысл tmp_buf
? Разве вы не можете читать прямо в buffer
?
да я на винде (бесплатно я забываю об этом на примере кода)
@gog цель tmp_buf
— хранить обработанные данные
мне нужно сделать это в 2 шага, потому что я отправляю все данные на устройство с libusb, поэтому я отключаю memcpy tmp_buf
, когда массив заполнен (я работаю на форке, поэтому я только редактирую данные перед отправка в буфер)
Поскольку вы говорите, что работаете над Windows , проблема заключается в том, что я обозначил в своем комментарии:
Ограничение размера стека в Windows составляет 1024 КБ (1 МБ), и вы пытаетесь создать в стеке буфер размером 1280 КБ. Используйте динамическое выделение памяти дважды. Даже в Unix-подобных системах ограничение размера стека обычно составляет 8 МБ, поэтому выделение такого большого массива в стеке немного сомнительно.
Поскольку ваша переменная tmp_buf
создается как локальная переменная в стеке, вы разрушаете стек в Windows. И в качестве
Я думаю, что ваша функция должна возвращать статус, чтобы указать, была ли она успешной или нет, поэтому я изменил тип возвращаемого значения на int
и использую 0
для обозначения успеха и -1
для отказа.
Это означает, что ваш код должен стать более похожим на:
enum { BUFFER_SIZE = 1310720 };
int read_input_file(FILE *stream, char *buffer)
{
long i = 0;
unsigned char *temp = malloc(BUFFER_SIZE);
unsigned char *calc = malloc(BUFFER_SIZE);
if (temp == NULL || calc == NULL)
{
free(temp); // Free both in case only one was allocated
free(calc);
return -1;
}
if (fread(calc, BUFFER_SIZE, 1, stream) != 1)
{
free(temp);
free(calc);
return -1;
}
for (size_t i = 0; i < BUFFER_SIZE; i++)
{
temp[i] = round(calc[i] / 128); //this is an example
}
memcpy(buffer, temp, BUFFER_SIZE);
free(temp);
free(calc);
return 0;
}
Я был бы счастливее, если бы длина buffer
была передана функции для проверки, но это решение, которое вы можете принять. Это не имеет решающего значения. Вы также можете использовать аргумент длины вместо фиксированного размера (теперь в перечисляемом значении), чтобы сделать ваш код более общим. Однако в данный момент вам может не понадобиться эта общность.
Также не ясно, что вы не можете избавиться от temp
(также известного как tmp_buf
), используя:
calc[i] = round(calc[i] / 128.0);
Обратите внимание на преобразование в константу с плавающей запятой; в противном случае округлять нечего, так как деление будет целочисленным. Однако, если в вычислении, отличном от примера, используются другие элементы calc
, а не только calc[i]
, вам понадобится второй массив для хранения результатов.
Спасибо за помощь, которая теперь работает нормально, также не знала о делении с плавающей запятой, и да, я использую другой элемент calc
, поэтому нужен временный буфер :)
Что происходит с кодом внизу? В чем проблема?