Недавно я снова начал пробовать C, язык, которым я не особенно владею и, по сути, постоянно забываю (я в основном кодирую Python). Моя идея состоит в том, чтобы читать данные из гипотетически большого файла в виде фрагментов, а затем обрабатывать данные соответствующим образом. На данный момент я моделирую это, фактически загружая весь файл в буфер типа short с помощью fread. Этот метод будет изменен, так как я бы подумал, что это будет очень плохая идея, скажем, для файла размером 1 ГБ. Конечная цель - прочитать фрагмент как один, обработать, переместить курсор, прочитать другой фрагмент и т. Д.
Размер рассматриваемого файла составляет 43 байта, и в нем есть фраза «Быстрая коричневая лисица прыгает через ленивого». собака". Этот размер удобен, потому что это простое число, поэтому независимо от того, на сколько байтов я его разделю, всегда будет мусор в конце (из-за того, что в буфере осталось свободное место?). Обработка данных в этом случае - это просто распечатка коротких строк в виде двух символов после манипуляции с байтами (см. Код ниже)
#include <stdio.h>
#include <stdlib.h>
#define MAX_BUFF_SIZE 1024
long file_size(FILE *f)
{
if (fseek(f, 0, SEEK_END) != 0) exit(EXIT_FAILURE); // Move cursor to the end
long file_size = ftell(f); // Determine position to get file size
rewind(f);
return file_size;
}
int main(int argc, char* argv[])
{
short buff[MAX_BUFF_SIZE] = {0}; // Initialize to 0 remove trailing garbage
char* filename = argv[1];
FILE* fp = fopen(filename, "r");
if (fp)
{
size_t size = sizeof(buff[0]); // Size in bytes of each chunk. Fixed to 2 bytes
int nmemb = (file_size(fp) + size - 1) / size; // Number of chunks to read from file
// (ceil f_size/size)
printf("Should read at most %d chunks\n", nmemb);
short mask = 0xFF; // Mask to take first or second byte
size_t num_read = fread(buff, size, nmemb, fp);
printf("Read %lu chunks\n\n", num_read); // Seems to have read more? Look into.
for (int i=0; i<nmemb; i++) {
char first_byte = buff[i] & mask;
char second_byte = (buff[i] >> 8) & mask; // Identity for 2 bytes. Keep mask for consistency
printf("Chunk %02d: 0x%04x | %c %c\n", // Remember little endian (bytes reversed)
i, buff[i], first_byte, second_byte);
}
fclose(fp);
} else
{
printf("File %s not found\n", filename);
return 1;
}
return 0;
}
Теперь, вчера, при распечатке последнего фрагмента данных, который я получил, «Chunk 21: 0xffff9567 | г ". Последний (первый?) Байт (0x67) - это g, и я ожидал некоторого мусора в конце, но я не понимаю, почему он печатал так много байтов, когда в переменной buff есть шорты. В тот момент я просто печатал шестнадцатеричный код как% x, а не% 04x, и buff не был инициализирован значением 0. Сегодня я решил инициализировать его значением 0, и не только исчез мусор, но и я. не могу воссоздать проблему даже после того, как оставил buff снова неинициализированным.
Итак, вот мои вопросы, которые, надеюсь, не слишком абстрактны:
- выглядит ли fread за пределами файла при чтении данных и удаляет ли он сам конечный мусор, или это зависит от нас?
- Почему printf показывает int, когда буфер короткий? (Я предполагаю, что% x предназначен для целых чисел), и почему я не могу воспроизвести поведение даже после того, как оставил buff без инициализации?
- Должен ли я всегда инициализировать буфер равным нулю, чтобы удалить завершающий мусор? Каков здесь обычный подход?
Надеюсь, это не слишком много или слишком расплывчатых вопросов, и я был достаточно ясен. Как я уже сказал, я мало знаю о C, но нахожу программирование низкого-среднего уровня очень интересным, особенно когда дело доходит до прямого манипулирования битами / байтами данных.
Надеюсь, у вас отличный день!
РЕДАКТИРОВАТЬ 1: Некоторые из вас мудро предложили использовать num_read вместо nmemb на l oop, так как это возвращаемое значение fread, но это означает, что я Отбросим остальную часть файла ( nmemb равно 22, а num_read равно 21). Это обычный подход? Кроме того, спасибо за то, что вы указали, что% x приводил к беззнаковому int, следовательно, 4 байта вместо 2.
EDIT 2: для пояснения, и, поскольку я ошибся в комментарии, я хотел бы сохранить оставшийся байт (или данные), отбрасывая остальные, которые не определены. Я не знаю, является ли это обычным подходом, поскольку, если я использую num_read в l oop, все, что остается в конце, отбрасывается, данные или нет. Мне больше интересно знать, каков обычный подход: отбросить оставшиеся данные или удалить все, что, как мы знаем, не определено, в данном случае один из байтов.