Arrays 在C语言中用memset实现整字而不是逐字节设置
因此,我试图实现我的个人Arrays 在C语言中用memset实现整字而不是逐字节设置,arrays,c,casting,byte,memset,Arrays,C,Casting,Byte,Memset,因此,我试图实现我的个人MemSet,这将与MemSet一样,但也: 尽可能复制字大小的块,而不是逐字节复制 保证目标的一致性 测试所有对准可能性 这是我的代码: void *MemSet(void *dest, int c, size_t n) { unsigned char *runner = (unsigned char *)dest; size_t i = 0; unsigned char swap_word[sizeof(size_
MemSet
,这将与MemSet
一样,但也:
- 尽可能复制字大小的块,而不是逐字节复制
- 保证目标的一致性
- 测试所有对准可能性
void *MemSet(void *dest, int c, size_t n)
{
unsigned char *runner = (unsigned char *)dest;
size_t i = 0;
unsigned char swap_word[sizeof(size_t)];
for (i = 0; i < sizeof(size_t); ++i)
{
swap_word[i] = (unsigned char)c;
}
if (NULL == dest)
{
return (NULL);
}
while (n > 0)
{
/* setting byte by byte */
if (n < sizeof(size_t) || (((size_t)runner & (sizeof(size_t) - 1)) != 0))
{
*runner++ = (unsigned char)c;
--n;
printf("Byte written\n"); /* for debugging */
}
else
{
/* setting a whole word */
*((void **)runner) = *((void **)swap_word);
runner += sizeof(size_t);
n -= sizeof(size_t);
printf("Word written\n"); /* for debugging */
}
}
return (dest);
}
输出为:
Before Memset, target is "2"
Before Memset, target is "3"
Word written
After Memset, target is "50529027"
After Memset, target is "50529027"
为什么元素不是“3”?他们两个?
我在这里用
MemSet(array, 3, 2 * sizeof(int))
理论上,这两个元素都需要设置为3
,因为数组在内存中使用2*sizeof(int)
空格,我将它们都设置为3
你觉得怎么样?
还有,我如何检查我的对齐是否有效
谢谢。您的函数有多个问题:
- 您可以在每次迭代中测试字大小的移动,这可能比简单的字节操作慢
*((void**)runner)=*((void**)swap\u word)代码>不正确,因为它违反了别名规则,并且
可能未正确对齐swap\u word
类型void*
- 第一个对齐目标指针的指针
- 第二个是设置完整的单词,一次可能不止一个
- 最后一个设置尾随字节(如果有的话)
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
// assuming uintptr_t has no padding bits
void *MemSet(void *dest, int c, size_t n) {
if (dest != NULL) {
unsigned char *p = dest;
if (n >= sizeof(uintptr_t)) {
// align destination pointer
// this test is not fully defined but works on all classic targets
while ((uintptr_t)p & (sizeof(uintptr_t) - 1)) {
*p++ = (unsigned char)c;
n--;
}
// compute word value (generalized chux formula)
uintptr_t w = UINTPTR_MAX / UCHAR_MAX * (unsigned char)c;
// added a redundant (void *) cast to prevent compiler warning
uintptr_t *pw = (uintptr_t *)(void *)p;
// set 16 or 32 bytes at a time
while (n >= 4 * sizeof(uintptr_t)) {
pw[0] = w;
pw[1] = w;
pw[2] = w;
pw[3] = w;
pw += 4;
n -= 4 * sizeof(uintptr_t);
}
// set the remaining 0 to 3 words
while (n >= sizeof(uintptr_t)) {
*pw++ = w;
n -= sizeof(uintptr_t);
}
p = (unsigned char *)pw;
}
// set the trailing bytes
while (n --> 0) {
*p++ = (unsigned char)c;
}
}
return dest;
}
#包括
#包括
#包括
//假设uintptr\u t没有填充位
void*MemSet(void*dest,int c,size\u t n){
如果(dest!=NULL){
无符号字符*p=dest;
如果(n>=sizeof(uintpttr\u t)){
//对齐目标指针
//此测试未完全定义,但适用于所有经典目标
而((uintpttr_t)p和(sizeof(uintpttr_t)-1)){
*p++=(无符号字符)c;
n--;
}
//计算字值(广义chux公式)
uintpttr_t w=uintpttr_MAX/UCHAR_MAX*(无符号字符)c;
//添加了冗余(void*)强制转换以防止编译器警告
uintptr_t*pw=(uintptr_t*)(void*)p;
//一次设置16或32字节
而(n>=4*sizeof(uintpttr\t)){
pw[0]=w;
pw[1]=w;
pw[2]=w;
pw[3]=w;
pw+=4;
n-=4*sizeof(uintpttr\t);
}
//将剩余的0设置为3个单词
而(n>=sizeof(uintpttr\t)){
*pw++=w;
n-=sizeof(uintptr\u t);
}
p=(无符号字符*)pw;
}
//设置尾随字节
而(n-->0){
*p++=(无符号字符)c;
}
}
返回目的地;
}
但是请注意,上述代码不太可能超过memset()
,因为:
- 如果已知目标指针已对齐或CPU允许未对齐的访问,编译器可能会将上述逻辑内联扩展为常量大小,从而跳过对齐测试
- 库可以使用专用指令,如SIMD或REP/STOS,根据实际目标CPU增加吞吐量
产生意外结果的原因是
int
跨越4个字节,每个字节都设置为3
,因此整数的结果值为0x03030303
,这正是50529027
与简单的字节型内存集相比,您的代码的开销正在抵消它可能具有的所有优势。@EugeneSh。我只是按照我任务的说明进行操作,如果可能的话,我必须添加这个设置一个完整单词的选项。候选替代(uintpttr_t)0x0101010101
-->uintpttr_MAX/0xFF
。现在不限于sizeof(uintpttr\t)@chux,谢谢!我发现了一个更一般的公式,允许使用非8位字节。。。仅假设没有填充位。而((uintpttr_t)p和(sizeof(uintpttr_t)-1))
是实现对齐的合理方法,但不是指定的方法。在C@NoobCoder中,无法按规范进行操作:我为您观察到的50529027
值添加了一个解释。复制上述代码以在注释中获得结果时,一定还有另一个问题。特别是关于发送到函数的字符串的含义是什么?它不起作用?@NoobCoder:sizeof(uintpttr\u t)-1
是一个位掩码,所有位都设置在对齐值之下while((uintptr\u t)p&mask)
相当于while((uintptr\u t)p&mask)!=0)
测试指针是否未对齐,即:设置了一个低位。
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
// assuming uintptr_t has no padding bits
void *MemSet(void *dest, int c, size_t n) {
if (dest != NULL) {
unsigned char *p = dest;
if (n >= sizeof(uintptr_t)) {
// align destination pointer
// this test is not fully defined but works on all classic targets
while ((uintptr_t)p & (sizeof(uintptr_t) - 1)) {
*p++ = (unsigned char)c;
n--;
}
// compute word value (generalized chux formula)
uintptr_t w = UINTPTR_MAX / UCHAR_MAX * (unsigned char)c;
// added a redundant (void *) cast to prevent compiler warning
uintptr_t *pw = (uintptr_t *)(void *)p;
// set 16 or 32 bytes at a time
while (n >= 4 * sizeof(uintptr_t)) {
pw[0] = w;
pw[1] = w;
pw[2] = w;
pw[3] = w;
pw += 4;
n -= 4 * sizeof(uintptr_t);
}
// set the remaining 0 to 3 words
while (n >= sizeof(uintptr_t)) {
*pw++ = w;
n -= sizeof(uintptr_t);
}
p = (unsigned char *)pw;
}
// set the trailing bytes
while (n --> 0) {
*p++ = (unsigned char)c;
}
}
return dest;
}