memset не заполняет массив

 u32 iterations = 5;
 u32* ecx = (u32*)malloc(sizeof(u32) * iterations);

 memset(ecx, 0xBAADF00D, sizeof(u32) * iterations);
 printf("%.8X\n", ecx[0]);

 ecx[0] = 0xBAADF00D;
 printf("%.8X\n", ecx[0]);

 free(ecx);

Проще говоря, почему мой вывод выглядит следующим образом?

0D0D0D0D
BAADF00D

ps: u32 - это простой typedef без знака int

редактировать:

  • Компиляция с помощью gcc 4.3.4
  • string.h включен

person Daniel Sloof    schedule 13.09.2009    source источник


Ответы (4)


Второй параметр memset имеет тип int, но на самом деле представляет собой символ без знака. . 0xBAADF00D, преобразованный в символ без знака (наименее значащий байт), равен 0x0D, поэтому memset заполняет память 0x0D.

person Tadmas    schedule 13.09.2009
comment
О, это довольно глупо. Каким будет наилучший подход к его заполнению? Просто перебирая его вручную, или есть функция, предназначенная для работы с более крупными типами, чем char? - person Daniel Sloof; 14.09.2009
comment
@Daniel, это глупо, потому что эта подпрограмма использует ассемблерную команду stosb для очень быстрой установки байтов, но не поддерживает stosw (слово) и stosd (двойное слово). - person Nick Dandoulakis; 14.09.2009
comment
@Daniel: если вы не считаете, что это узкое место в производительности, написание простого цикла - лучший способ. - person Tadmas; 14.09.2009
comment
См. также stackoverflow.com/questions/108866/ - person Tadmas; 14.09.2009
comment
Причина, по которой memset принимает int, хотя на самом деле ему требуется unsigned char, заключается в том, что он датируется днями до ANSI C, когда были представлены прототипы функций. Аргументы непрототипированных функций расширены до int / unsigned int, поэтому, чтобы сделать прототип определения ANSI C для memset совместимым со старым непрототипным определением, он должен был принять int. - person caf; 14.09.2009

Второй аргумент memset() — это char, а не int или u32. C автоматически усекает 0xBAADF00D int до 0x0D char и устанавливает каждый символ в памяти по запросу.

person George Phillips    schedule 13.09.2009

Я попробовал это с помощью wmemset(). Кажется, это работает:


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

int main(void){
  uint32_t iterations = 5;
  uint32_t *ecx = (uint32_t*)malloc(sizeof(uint32_t) * iterations);

  wmemset( (wchar_t*)ecx, 0xBAADF00D, sizeof(uint32_t) * iterations);
  printf("%.8X\n", ecx[0]);

  ecx[0] = 0xBAADF00D;
  printf("%.8X\n", ecx[0]);

  /* Update: filling the array with memcpy() */
  ecx[0] = 0x11223344;
  memcpy( ecx+1, ecx, sizeof(*ecx) * (iterations-1) );
  printf("memcpy:   %.8X %.8X %.8X %.8X %.8X\n",
             ecx[0], ecx[1], ecx[2], ecx[3], ecx[4] );
}
person sambowry    schedule 13.09.2009
comment
Я думаю, что причина, по которой за вас проголосовали, заключается в том, что wmemset принимает широкий символьный аргумент (также известный как wchar_t), который составляет 16 бит, а не 32. Но это интересно: я никогда не знал, что эта функция существует. Аккуратный. - person Tadmas; 14.09.2009
comment
что на выходе? 0D0D0D0D? F00DF00D? - person Pod; 14.09.2009
comment
Не обращайте внимания на мой предыдущий комментарий, я думал, что wmemset у вас не работает, но это так :) - person Pod; 14.09.2009
comment
@sambowry: я думаю, это зависит от реализации. Он основан на базовом целочисленном типе, поэтому ваш компилятор мог выбрать int вместо short. После небольшого поиска в Google оказалось, что wchar_t обычно составляет 2 байта в Windows и 4 байта в Linux/Mac. Поскольку спрашивающий использует gcc, вероятно, это Linux, так что это сработает для него. Тем не менее, это не совсем портативный. Хорошее решение. +1 - person Tadmas; 14.09.2009

Трюк с memcpy( ecx+1, ecx, ... не работает в Linux. Копируется только 1 байт вместо iterations-1.

person CoSoCo    schedule 19.04.2019