Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在C语言中用memset实现整字而不是逐字节设置_Arrays_C_Casting_Byte_Memset - Fatal编程技术网

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