如何有效地将内存块与单个字节进行比较?

时间:2014-08-06 16:59:34

标签: c memcmp

我正在尝试查看结构是否以结构大小的全部0xFF的形式返回。

memcmp似乎是一个明显的起点,但我必须分配第二个内存块,用0xFF填充它。这似乎是一种浪费。

这是否存在标准功能?或者我应该通过for循环进行ping和迭代?

7 个答案:

答案 0 :(得分:4)

我知道没有标准功能。

我不认为memcmp总是正确的选择(它需要两倍的内存带宽)。

我会写一个迭代(甚至是一个非常天真的)。大多数编译器都非常好地优化(当被问及时)。所以他们可能会展开你的循环并可能进行单词比较(即使你编写了一个天真的字节迭代)。

您可以编写专门的openmp变体(至少在GCC上)。见http://openmp.org/

如果结构很大(例如几十千字节,由于GPGPU的RAM数据副本的成本),如果你有大量的开发时间浪费,可考虑OpenCL(特别是如果你有专门的硬件支持它,例如GPGPU)。它可能永远不值得花费(除非你做的事情 - 在GPGPU工作时CPU上不需要大量的内存带宽)

我会编写天真的循环,并且不会手动优化(除非编译优化代码的基准测试另有建议),因为瓶颈可能是内存带宽。

答案 1 :(得分:4)

这里最明显的解决方案似乎是简单地循环结构的大小并逐字节地进行比较。

分配0xFF后跟memcmp的块的方法应该达到相同但空间复杂度更高。

答案 2 :(得分:3)

此类函数的逻辑名称为memcchr - memchrstrcspnstrspn

看看这里:google results for memcchr表明它是作为FreeBSD内核的一部分在该名称下实现的,并且他们已经尝试优化它超出明显的1字节at-a-a时间循环。

使这个函数适合在除FreeBSD内核之外的任何程序中使用可能还需要一些额外的工作。

答案 3 :(得分:2)

有memchr(),它与你要求的相反 - 搜索mem块中第一次出现的字节。 afaik,没有标准函数来搜索与特定字节不匹配的字节。 for loop听起来像是要走的路。也许一次去32/64位加速它。

- 额外的不答案:memcmp将比for循环慢。首先,您需要填充与原始块大小相同的内存块(此部分可能需要与原始循环一样长)。然后,您需要将每个内存块读入寄存器以进行比较。 for循环将在寄存器中有一个值,只读入一个存储块以与不变的寄存器进行比较。

答案 4 :(得分:2)

我不知道这对性能有多大帮助,但你可以遵循这个算法:

  1. 将结构的第一个字节与1个字节的已分配内存0xFF
  2. 进行比较
  3. 将struct的第二个字节与struct的第一个字节进行比较
  4. 将struct的字节3-4与struct
  5. 的字节1-2进行比较
  6. 将struct的字节5-8与struct
  7. 的字节1-4进行比较

    继续以相同的方式直到结构的结尾。如果语句在任何时候都是假的,那么你知道结构不是全0xFF。当结构的剩余部分小于检查的第一部分时,您还需要以不同的方式处理它,但这应该相对简单。

    最后,你已经分配了1个额外字节的内存,算法是O(log n)(到目前为止我在答案中看到的情况略有改善)。

    编辑:正如下面提到的escrafford,如果你替换" byte" for" word"在上面的部分,它可能会运行一点点。我无法评论你可能获得多少速度,但它会增加存储的额外内存(尽管今天的计算机只有很少的数量)。

答案 5 :(得分:0)

Why does this implementation of strlen() work?中重写脏代码。做了一些快速测试;没有保证。

这应该返回0xFF个字节的数量;如果它等于你开始使用的数字,那么你就是安全的。 (当然,您也可以让它返回01。)满意时删除printf

#define LONGPTR_MASK (sizeof(long) - 1)

int find_no_ff (const char *memory, size_t length)
{
    const char *p;
    const unsigned long *lp;
    size_t remain = length, to_do;

    printf ("non-aligned, start:\n");
    /* Test the first few bytes until we have an aligned p */
    for (p = memory; (uintptr_t)p & LONGPTR_MASK; p++)
    {
        printf ("testing %02X\n", *p & 0xff);
        if (*p != '\xFF')
            return (p - memory);
        remain--;
    }

    printf ("passed.\n");

    printf ("aligned:\n");
    to_do = remain/sizeof(long);
    remain -= (to_do*sizeof(long));

    /* Scan the rest of the string using word sized operation */
    for (lp = (const unsigned long *)p; to_do--; lp++)
    {
        printf ("testing %08lX\n", *lp);
        if (*lp +1)
            return p - memory;
    }
    printf ("passed.\n");

    p = (const char *)lp;

    printf ("non-aligned, end:\n");
    /* Test the last bytes until we have an aligned p */
    while (remain--)
    {
        printf ("testing %02X\n", *p & 0xff);
        if (*p != '\xFF')
            return (p - memory);
        p++;
    }
    printf ("passed.\n");
    return p - memory;
}

int main (void)
{
    char data[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,  0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };

    printf ("input size: %ld\n", sizeof(data));
    printf ("test result: %d\n", find_no_ff (data, sizeof(data)));

    return 0;
}

答案 6 :(得分:0)

我喜欢Erik的建议,但可以通过以下有趣的方式进行简化(未经测试):

if((* pBytes == 0xFF)&&(memcmp(pBytes,pBytes + 1,byteCount - 1)== 0))     // pBytes处的byteCount字节是0xFF。

只有当A)第一个字节为0xFF且B)每隔一个字节等于它之前的字节时,条件才为真。组合意味着每个字节都是0xFF。