Поменяйте местами указатели вместо memcpy - PullRequest
3 голосов
/ 28 марта 2011

РЕДАКТИРОВАТЬ : Извините за ошибки в моих фрагментах кода, теперь я вижу, что оба вывода были одинаковыми.Ниже отредактированная версия.

Допустим, у меня есть структура:

typedef struct
{
    char m[5];
    char f[6];
} COUPLE;

И файл, содержащий только фразу RomeoJuliet, которую я прочитал в массив:

char *data = malloc(11);
FILE *f = fopen("myfile", "rb");
fread(data, 1, 11, f);
fclose(f);

Я всегда использую этот код, когда мне нужно заполнить свою структуру из байтового массива:

COUPLE titanic;
memcpy(&titanic, data, sizeof(data));
printf("%s and %s", titanic.m, titanic.f);

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

COUPLE *titanic = (COUPLE *)data;
printf("%s and %s", titanic->m, titanic->f);

Итак, мои вопросы:

  1. (устарел). Почему я получаю разные выходные данные?
  2. (устарел). Как я могу заполнитьструктура просто путем приведения из массива?
  3. Стоит ли избегать такого рода оптимизации?
  4. Есть ли в ней возможные подводные камни?

Ответы [ 4 ]

2 голосов
/ 28 марта 2011

То, что вы говорите, не соответствует действительности. Вы используете метод, если заполнение структуры из строки мое использование memcpy не будет и не работает. Во-первых, когда вы делаете

memcpy(&titanic, data, sizeof(data));

вы копируете 12 байтов из массива char. Между тем не гарантируется, что структура будет иметь размер 12 байт (общий размер - только 11), поэтому в общем случае это приведет к переполнению памяти.

Во-вторых, массив символов в titanic.m не будет заканчиваться нулем. То же самое верно для titanic.f, поэтому ваш printf не имеет абсолютно никаких изменений в выводе "Romeo and Juliet", как вы ошибочно утверждаете.

Вы утверждаете, что ваш первый пример "работает нормально" (почему?), Тогда как в действительности первый пример вообще не работает, и даже когда он "работает", он страдает от проблем, очень похожих на ваш второй пример (хотя в общем случае точные проблемы не будут предсказуемыми).

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

1 голос
/ 28 марта 2011

Я думаю, что единственным решением, которое не использует memcpy, было бы решение, которое непосредственно считывало из файла в структуру. Это может быть что-то вроде этого

typedef struct
{
    char m[6];
    char f[7];
} COUPLE;

COUPLE titanic;

FILE *f = fopen("myfile", "rb");
fread(titanic.m, 1, 5, f);
titanic.m[5] = '\0';
fread(titanic.f, 1, 6, f);
titanic.f[6] = '\0';
fclose(f);

printf("%s and %s", titanic.m, titanic.f);

Конечно, этот пример, вероятно, не оптимален, потому что я думаю, что один вызов fread и несколько memcpy будет быстрее, чем 2 fread. Так или иначе, оба решения очень нереалистичны, потому что проблема нереальна - кому нужна структура, в которой хранится имя длиной 5 и 6 символов.

1 голос
/ 28 марта 2011

Когда я прокомментировал ваш вопрос, у меня не было времени на детали, поэтому я попытаюсь ответить. С тех пор код изменился, и я не уверен, что добавил бы этот комментарий к коду, как сейчас.

Тем не менее, основная причина, побудившая меня добавить этот комментарий, остается в силе: Если вы не измерили и не обнаружили, что рассматриваемый код действительно оказывает существенное негативное влияние на производительность, не пытайтесь оптимизировать . Вместо этого постарайтесь сделать ваш код максимально читабельным .

Я серьезно сомневаюсь, что копирование данных в память окажет значительное влияние на производительность после копирования их с диска в память. Тем не менее, поскольку ваш код в соответствии с предоставленными данными в любом случае делает предположения о расположении структуры в памяти, непосредственное чтение структуры не сделает код менее читабельным (или менее уязвимым для изменений в этом расположении):

COUPLE titanic;
FILE *f = fopen("myfile", "rb");
fread(&titanic, sizeof(titanic), 1, f);

Или, если у вас действительно есть массив, прочитайте непосредственно в массив:

COUPLE titanic[SIZE];
FILE *f = fopen("myfile", "rb");
fread(&titanic, sizeof(titanic), SIZE, f);

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

1 голос
/ 28 марта 2011
  1. Потому что это члены начинают с другой позиции. Printf () печатает нулевое (\ 0) завершенное предложение.
  2. Вы можете сделать это так. Но нужно обратить внимание на типы и способы их использования.
  3. Это может быть хорошо, если вы знаете, что делаете.
  4. Много ловушек, если вы не знаете, что делаете ... Нет безопасности типов.
...