memset无法填充数组

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

非常简单地说,为什么我的输出结果是以下内容?
0D0D0D0D
BAADF00D

提示:

u32是unsigned int的简单typedef

编辑:

  • 使用gcc 4.3.4编译
  • 已包含string.h头文件
4个回答

11

memset的第二个参数被定义为int类型,但实际上它是无符号字符unsigned char。0xBAADF00D转换为无符号字符(最低有效位)即为0x0D,因此memset会以0x0D填充内存。


哦,那真是有点傻。怎样才能最好地填充它呢?是手动循环遍历,还是有专门处理比char更大类型的函数? - Daniel Sloof
4
@Daniel,这个例程使用stosb汇编命令来快速设置字节,这很愚蠢,因为它不支持stosw(字)和stosd(双字)。 - Nick Dandoulakis
@Daniel:除非你测量出它是性能瓶颈,否则编写简单的循环是最好的选择。 - Tadmas
参见https://dev59.com/73VD5IYBdhLWcg3wDG_m - Tadmas
4
memset函数之所以要接收一个int类型的参数,尽管它实际上需要的是一个unsigned char类型的参数,是因为它的历史可以追溯到ANSI C标准出现之前的时期,当时还没有函数原型。在没有函数原型的情况下调用函数时,参数会被扩展为intunsigned int类型,所以为了让ANSI C标准下的函数原型与旧的非函数原型定义兼容,就必须使用int类型作为参数。 - caf

2

我使用了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] );
}

1
我认为你被踩的原因是wmemset接受宽字符参数(也称为wchar_t),它是16位而不是32位。但这很有趣:我从来不知道这个函数的存在。很棒。 - Tadmas
输出是什么? 0D0D0D0D?F00DF00D? - Pod
忽略我的先前评论,我以为wmemset对你不起作用,但它是有效的 :) - Pod
@sambowry:我猜这取决于实现方式。它基于底层整数类型,所以编译器可能选择int而不是short。经过一番搜索,看起来wchar_t在Windows上通常为2个字节,在Linux/Mac上为4个字节。由于提问者正在使用gcc,所以他可能是在Linux上,所以这对他来说是可行的。但仍然不太具有可移植性。好的解决方案。+1 - Tadmas

2

memset()函数的第二个参数是char类型,而不是int或者u32。C语言会自动将0xBAADF00D截断为0x0D,然后按照请求设置内存中的每个字符。


0

memcpy(ecx+1, ecx, ... 的技巧在 Linux 上不起作用,只有 1 字节被复制,而不是 iterations-1


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接