4
 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);

Very simply put, why is my output the following?

0D0D0D0D
BAADF00D

ps: u32 is a simple typedef of unsigned int

edit:

  • Compiling with gcc 4.3.4
  • string.h is included
Daniel Sloof
  • 12,568
  • 14
  • 72
  • 106

4 Answers4

11

The second parameter to memset is typed as an int but is really an unsigned char. 0xBAADF00D converted to an unsigned char (least significant byte) is 0x0D, so memset fills memory with 0x0D.

Tadmas
  • 6,238
  • 3
  • 39
  • 31
  • Oh, that is quite silly. What would be the best approach of going about filling it? Just looping over it manually, or is there a function designed for dealing with larger types than char? – Daniel Sloof Sep 13 '09 at 21:24
  • 4
    @Daniel, it's *silly* because that routine uses the `stosb` assembly command to set the bytes very fast, but it doesn't support the `stosw` (word) & `stosd` (dword). – Nick Dandoulakis Sep 13 '09 at 21:35
  • @Daniel: unless you measure it to be a performance bottleneck, writing a simple loop is the best way to go. – Tadmas Sep 13 '09 at 21:40
  • See also http://stackoverflow.com/questions/108866/is-there-memset-that-accepts-integers-larger-than-char – Tadmas Sep 13 '09 at 21:42
  • 4
    The reason that `memset` takes an `int` even though it really wants an `unsigned char` is that it dates from the days before ANSI C, when function prototypes were introduced. Arguments to unprototyped functions are widened to `int` / `unsigned int`, so to make the prototyped ANSI C definition of `memset` compatible with the old unprototyped definition, it had to take `int`. – caf Sep 14 '09 at 00:21
2

The second argument to memset() is a char not a int or u32. C automatically truncates the 0xBAADF00D int into a 0x0D char and sets each character in memory as requested.

George Phillips
  • 4,564
  • 27
  • 25
2

I tried it with wmemset(). It seems to work:


#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] );
}
sambowry
  • 2,436
  • 1
  • 16
  • 13
  • 1
    I think the reason you got downvoted is that wmemset takes a wide character argument (aka wchar_t), which is 16 bits, not 32. But that's interesting: I never knew that function existed. Neat. – Tadmas Sep 14 '09 at 01:33
  • what's the output? 0D0D0D0D? F00DF00D? – Pod Sep 14 '09 at 13:36
  • Ignore my previous comment, I thought that wmemset wasn't working for you, but it is :) – Pod Sep 14 '09 at 13:39
  • @sambowry: I guess it depends on the implementation. It's based on an underlying integral type, so your compiler may have chosen int instead of short. After googling a bit, it looks like wchar_t is typically 2 bytes on Windows and 4 bytes on Linux/Mac. Since the asker is using gcc, it's probably Linux, so this would work for him. Still, it's not really portable. Nice solution. +1 – Tadmas Sep 14 '09 at 14:49
0

The trick with memcpy( ecx+1, ecx, ... does not work here on Linux. Only 1 byte is copied instead of iterations-1.

CoSoCo
  • 71
  • 1
  • 8