1. Когда я использую fwrite to stdout, это становится неопределенным результатом?
  2. Какая польза от аргумента size_t count в функциях fwrite и fread?
#include<stdio.h>

struct test
{
   char str[20];
   int num;
   float fnum;
}; 

int main()
{
   struct test test1={"name",12,12.334};

   fwrite(&test1,sizeof(test1),1,stdout);

   return 0;
}

Выход:

 name                   XEA
 Process returned 0 (0x0)   execution time : 0.180 s
 Press any key to continue.

И когда я использую FWRITE для файла

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

 struct test
 {
  char str[20];
  int num;
  float fnum;
 };

 int main()
 {
 struct test test1={"name",12,12.334};
 FILE *fp;

 fp=fopen("test.txt","w");

 if(fp==NULL)
 {
   printf("FILE Error");
   exit(1);
 }

 fwrite(&test1,sizeof(test1),1,fp);

 return 0;
 }

Файл также содержит подобное

 name                   XEA
  1. Почему вывод такой?
  2. И когда я ставлю size_t count как 5, он также становится неопределенным результатом. Какова цель этого аргумента?
c
-4
user12129618 6 Окт 2019 в 09:37

1 ответ

Лучший ответ

Таким образом, вы используете его, fwrite - это запись «двоичного» выхода, которое представляет собой байтовое представление вашего struct test, как в памяти. Это представление не , как правило, читаемое человеком.

Когда ты пишешь

struct test test1 = {"name", 12, 12.334};

Вы получаете структуру в памяти, которая может быть представлена ​​следующим образом (со всеми байтовыми значениями в шестнадцатеричном формате):

test1: str: 6e 61 6d 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
       num: 0c 00 00 00
      fnum: 10 58 45 41

В частности: 0x6e, 0x6d, 0x6d, а 0x65, и 0x65 - коды ASCII для букв в "name". Ваш массив {str был размером 20, поэтому строка name равен 0, а затем прокладывается с 15 более 0 символов. 0x0c - шестнадцатеричное представление № 12, и я предполагаю, что тип int - 32 бита или 4 байта на вашем компьютере, поэтому есть еще 3 0, также. (Также я предполагаю, что ваша машина - «маленький Endian», с наименее значимым байтом 4-байтового количества, подобного 0x0000000c, находящихся первым в памяти.) Наконец, в формат IEEE-754 который использует вашу машину, номер 12.334 представлен в 32-разрядной точке с плавающей точкой одной точности AS {{x10} }, который снова хранится в противоположном порядке в памяти.

Таким образом, эти 28 байтов (плюс, возможно, некоторые дополнения, о которых мы пока не будем беспокоиться) - это именно те байты, которые записываются на экран или в ваш файл. Строка «name», вероятно, будет удобочитаема, но все остальное будет буквально «двоичным мусором. ". Так уж получилось, что три байта, составляющие число с плавающей запятой 12.334, а именно 0x58, 0x45 и 0x41, соответствуют в ASCII заглавным буквам X, { {X4}} и A, поэтому вы видите эти символы в выводе.

Вот результат прохождения вывода вашей программы в «Hex Dump Утилита:

 0  6e 61 6d 65 00 00 00 00  00 00 00 00 00 00 00 00   name............
16  00 00 00 00 0c 00 00 00  10 58 45 41               .........XEA    

Вы можете видеть буквы name в начале и буквы XEA в конце, а также все нули и другие двоичные символы между ними.

Если вы находитесь в системе Unix или Linux (или Mac OS X), вы можете использовать такие инструменты, как od или hexdump, чтобы получить Шестник свалка, похожий на тот, который я показал.


Вы спросили об аргументе "счетчик" для fwrite. fwrite буквально предназначен для записи двоичных структур, как и вы. Его функциональная подпись

size_t fwrite(void *ptr, size_t sz, size_t n, FILE *fp);

Как вы знаете, ptr - указатель на структуру (ы) данных, которые вы пишете, и fp указатель файла вы пишете это / их. И тогда вы говорите, что хотите написать n (или «count») элементы, каждый размер sz.

Вы назвали

fwrite(&test1, sizeof(test1), 1, fp);

Выражение sizeof(test1) дает размер test1 в байтах. (Вероятно, будет 28 или около того, как я упоминал выше.) И, конечно, вы пишете одну структуру, поэтому передаете sizeof(test1) и 1 как sz и n совершенно разумно и правильно.

Это также не было бы неразумно или неверно позвонить

fwrite(&test1, 1, sizeof(test1), fp);

Теперь вы говорите fwrite записать 28 байтов, каждый размером 1. (Байт, конечно, всегда имеет размер 1.)

Еще одна вещь о fwrite (как отмечено @anttihaapala в комментарии): когда вы пишете двоичные данные в файл, вы должны указать флаг b, когда вы открываете файл:

fp = fopen("test.txt", "wb");

Наконец, если это не то, что вам нужно, если вместо этого вы хотите выводить текст, читаемый человеком, то {{X 0}} здесь не то, что вам нужно. Вы можете использовать что-то вроде

printf("str: %s\n", test1.str);
printf("num: %d\n", test1.num);
printf("fnum: %f\n", test1.fnum);

Или к вашему файлу:

fprintf(fp, "str: %s\n", test1.str);
fprintf(fp, "num: %d\n", test1.num);
fprintf(fp, "fnum: %f\n", test1.fnum);
1
Steve Summit 6 Окт 2019 в 12:15