Печать побайтно

Я пытаюсь создать программу C, которая открывает файл и печатает его байт за байтом, используя формат Hexabyte (% 02x) для каждого байта.

Результат должен быть примерно таким:

$ ./hexabyte file
43
3d
67
...

Я знаю, что хочу использовать для этого fread, но не уверен, почему это решение не работает:

#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>


int args_test(int args, char path[]){

  if (args < 1){
    fprintf(stderr, "Usage: %s path\n", path);
    exit(EXIT_SUCCESS);
  }
  if (args < 2){
    fprintf(stderr, "Usage: %s path\n", path);
    exit(EXIT_SUCCESS);
  }

  if (args > 2){
    fprintf(stderr, "Usage: %s path\n", path);
    exit(EXIT_SUCCESS);
  }

  return 0;
}


int open_file(char path[]){
  FILE *fp;
  fp = fopen(path, "r");
  char buffer[1000];

  if (!fp){
    fprintf(stderr, "%s\n", strerror(errno));
    return EXIT_FAILURE;
  }

  fseek(fp, 0, SEEK_END);
  int len = ftell(fp);

  //Why does it not reach this loop?
  while (fread(buffer, strlen(path), 1, fp) == 1){
    printf("%02x hexabytes\n", len);
  }

  fclose(fp);

  exit(EXIT_SUCCESS);
}

int main(int args, char* argv[]){
  if (args < 2 || args > 2){
    args_test(args, argv[0]);
  }
  args_test(args, argv[1]);
  open_file(argv[1]);
  exit(EXIT_SUCCESS);
}

Кажется, что он никогда не достигает моего цикла while, и поэтому никогда ничего не печатает

if (args < 2 || args > 2) == if (args != 2);)
hellow 19.09.2018 15:27

Хаха спасибо. Конечно :)

DonutSteve 19.09.2018 15:29

Не рекомендуется выходить из функции, используйте вместо этого возврат

hellow 19.09.2018 15:32

Если вы используете свою функцию, например, библиотека, и она внезапно перестает работать, потому что произошла ошибка, и вы выполняете exit(1), это не ожидаемое поведение. Конечно, это нормально для таких небольших примеров, но это недопустимо для большой (r) кодовой базы.

hellow 19.09.2018 15:34

Отладчик - ваш друг. А за документацию: любой учебник C. Вы не можете научиться программированию, копируя / вставляя фрагменты. Программа - это не лоскутное одеяло.

too honest for this site 19.09.2018 15:38

@hellow: exit в порядке, если вы хотеть для выхода. Речь не о рекомендациях, а о различных функциях.

too honest for this site 19.09.2018 15:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
6
112
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Вам нужно сбросить указатель файла на начало файла:

fseek(fp, 0, SEEK_SET);

Это помогло. Теперь он не выводит никаких значений, так что мне тоже придется разобраться в этом. Думал, что он должен работать, когда он вошел в цикл. Хм.

DonutSteve 19.09.2018 15:31

@kthonenice, потому что вы печатаете printf("%02x hexabytes\n", len);, а не фактический буфер, который вы читаете

hellow 19.09.2018 15:31

Да, но если я попытаюсь добавить буфер вместо len, мне нужно будет изменить формат с% 02x?

DonutSteve 19.09.2018 15:32

Возьмите, пожалуйста, учебник. Этот сайт предназначен для вопросов специфический о проблемах специфический, а не для обучения. Вы не научитесь C, задавая единичные вопросы, вам нужны основы.

too honest for this site 19.09.2018 15:41
Ответ принят как подходящий

Вы стремитесь к концу файла, поэтому fread нечего будет читать. Вам нужно вернуться к началу.

fread также просят прочитать длину пути, что кажется неправильным, так как ваш цикл настроен для 1 байта за раз.

fseek(fp, 0, SEEK_END); // Seeks to end of file
int len = ftell(fp);

// Nothing to read, at end
while (fread(buffer, strlen(path), 1, fp) == 1){
    printf("%02x hexabytes\n", len);
}

Просто снова найдите ftell.

fseek(fp, 0, SEEK_END); // Seeks to end of file
int len = ftell(fp);
fseek(fp, 0, SEEK_SET); // Go to start again
// Read from start, 1 byte at a time
char byte;
while (fread(&byte, 1, 1, fp) == 1){
    printf("%02X\n", (int)byte);
}

Вы также можете читать 1000 байт за раз (как ваш buffer), но тогда вам понадобится второй цикл, или вы можете прочитать весь файл, но вам нужно динамически выделить буфер (buffer = malloc(len);).

Спасибо за разъяснения. Теперь я вижу, что мой файл уже был в конце. Интересно, как работает ваш байт char. В примере, который я искал, указан размер, как и в случае с моим начальным буфером, но вы делаете что-то другое, как я вижу. Не совсем уверен, как ваш fread работает по сравнению с моим, но похоже, что ваша реализация работает так, как я предполагал, моя должна!

DonutSteve 19.09.2018 15:39

Цикл читает по одному байту за раз, чтение больших объемов за один раз часто используется для повышения производительности, но тогда для этого вам все равно понадобится 1 printf на байт или для форматирования строки другими способами.

Fire Lancer 19.09.2018 15:41

Просто нужно найти базовый синтаксис, чтобы убедиться, что я все понимаю. Но спасибо, что сообщили мне, где я напортачил! Очень признателен!

DonutSteve 19.09.2018 15:44

Даже если вы исправите проблему с fseek, у вас останутся другие проблемы:

while (fread(buffer, strlen(path), 1, fp) == 1){
  printf("%02x hexabytes\n", len);
}

Обратите внимание, что вы не читаете по одному байту за раз; вы читаете байты кусками размера strlen(path) за раз.

Вы также не печатаете только что прочитанные байты; вы печатаете длина файла. Предполагая, что размер вашего файла составляет, скажем, 65536 байт, вы получите результат

10000 hexabytes
10000 hexabytes
10000 hexabytes
...

65536 / strlen(path) раза. Не думаю, что ты этого хочешь.

Я думаю, что вы собираетесь сделать что-то в этом роде:

unsigned char buffer[1000]; // for arbitrary bytes, unsigned char works better.

int bytes_read = 0;

while ( (bytes_read = fread( buffer, 1, sizeof buffer, fp )) != EOF )
{
  for( int b = 0; b < bytes_read; b++ )
  {
    printf( "%02hhx\n", buffer[b] ); // %x expects unsigned *int*, use the
  }                                  // hh modifier to specify unsigned char
}

Выражение

bytes_read = fread( buffer, 1, sizeof buffer, fp )

считывает до sizeof buffer (в данном случае 1000) байтов из fp и сохраняет фактически прочитанное число в bytes_read. Если мы не попали в EOF, то печатаем содержимое buffer.

Другие вопросы по теме