7

似乎无法在任何地方找到答案,如何将数组设置为数组类型的最大值?我原以为memset(ZBUFFER,0xFFFF,size)ZBUFFER 是一个 16 位整数数组的地方会起作用。相反,我始终得到-1。

此外,我们的想法是尽可能快地完成这项工作(它是一个需要初始化每一帧的 zbuffer),所以如果有更好的方法(并且仍然一样快或更快),请告诉我。

编辑:作为澄清,我确实需要一个带符号的 int 数组。

4

9 回答 9

9

C++中,您将使用 std::fill 和 std::numeric_limits。

#include <algorithm>
#include <iterator>
#include <limits>

template <typename IT>
void FillWithMax( IT first, IT last )
{
    typedef typename std::iterator_traits<IT>::value_type T;
    T const maxval = std::numeric_limits<T>::max();
    std::fill( first, last, maxval );
}

size_t const size=32;
short ZBUFFER[size];
FillWithMax( ZBUFFER, &ZBUFFER[0]+size );

这适用于任何类型。

C中,您最好不要memset设置字节的值。char要初始化(ev. )以外的其他类型的数组unsigned,您必须求助于手动for循环。

于 2013-04-11T11:58:44.140 回答
7

-1 和 0xFFFF 在使用二进制补码表示的 16 位整数中是相同的。您只得到 -1 是因为您已将数组声明为short而不是unsigned short. 或者因为您在输出它们时将值转换为有符号。

顺便说一句,您假设您可以使用 memset设置字节以外的内容是错误的。memset(ZBUFFER, 0xFF, size)会做同样的事情。

于 2013-04-11T11:49:07.887 回答
4

在 C++ 中,您可以使用算法为数组填充一些值std::fill

std::fill(ZBUFFER, ZBUFFER+size, std::numeric_limits<short>::max());

这既不比您当前的方法快也不慢。不过,它确实有工作的好处。

于 2013-04-11T11:59:04.777 回答
3

不要将速度归因于语言。那是为了 C 的实现。有些 C 编译器可以生成快速、优化的机器代码,而 C 编译器可以生成慢速、非优化的机器代码。对于 C++ 也是如此。“快速、最佳”的实现可能能够优化看起来很慢的代码。因此,调用一个解决方案比另一个更快是没有意义的。我会谈论正确性,然后我会谈论性能,无论它多么微不足道。最好对代码进行概要分析,以确保这实际上是瓶颈,但让我们继续。

让我们首先考虑最明智的选择:复制int值的循环。只需阅读循环将正确分配SHRT_MAX给每个int项目的代码,就可以清楚地看到。您可以在下面看到此循环的测试用例,它将尝试使用当时可分配的最大可能数组malloc

#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    size_t size = SIZE_MAX;
    volatile int *array = malloc(size);

    /* Allocate largest array */
    while (array == NULL && size > 0) {
        size >>= 1;
        array = malloc(size);
    }

    printf("Copying into %zu bytes\n", size);

    for (size_t n = 0; n < size / sizeof *array; n++) {
        array[n] = SHRT_MAX;
    }

    puts("Done!");
    return 0;
}

我在我的系统上运行了它,编译时启用了各种优化(-O3 -march=core2 -funroll-loops)。这是输出:

Copying into 1073741823 bytes
Done!

Process returned 0 (0x0)   execution time : 1.094 s
Press any key to continue.

注意“执行时间”......这非常快!如果有的话,这里的瓶颈是这样一个大数组的缓存局部性,这就是为什么一个好的程序员会尝试设计不使用这么多内存的系统......好吧,那么让我们考虑 memset 选项。这是memset 手册的引述:

memset() 函数将 c(转换为unsigned char)复制到 s 指向的对象的前 n 个字节中。

因此,它将 0xFFFF 转换为无符号字符(并可能截断该值),然后将转换后的值分配给第一个size字节。这会导致不正确的行为。我不喜欢依赖值 SHRT_MAX 来表示为存储 value 的字节序列(unsigned char) 0xFFFF,因为这依赖于巧合。换句话说,这里的主要问题是 memset 不适合您的任务。不要使用它。话虽如此,这里有一个测试,源自上面的测试,将用于测试 memset 的速度:

#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(void) {
    size_t size = SIZE_MAX;
    volatile int *array = malloc(size);

    /* Allocate largest array */
    while (array == NULL && size > 0) {
        size >>= 1;
        array = malloc(size);
    }

    printf("Copying into %zu bytes\n", size);

    memset(array, 0xFFFF, size);

    puts("Done!");
    return 0;
}

一个简单的字节复制 memset 循环将比sizeof (int)我的第一个示例中的循环迭代次数多。考虑到我的实现使用了相当优化的 memset,输出如下:

Copying into 1073741823 bytes
Done!

Process returned 0 (0x0)   execution time : 1.060 s
Press any key to continue.

这些测试可能会有所不同,但差异很大。我每个人只运行一次以获得一个粗略的想法。希望您得出与我相同的结论:普通编译器非常擅长优化简单循环,因此不值得在这里假设微优化。

总之:

  1. 不要使用 memset 用值填充整数(值 0 除外),因为它不适合。
  2. 不要在运行测试之前假设优化。在找到可行的解决方案之前不要运行测试。通过工作解决方案,我的意思是“解决实际问题的程序”。一旦你有了这个,使用你的分析器来确定更重要的优化机会!
于 2013-04-11T15:31:13.227 回答
2

这是因为补码。您必须将数组类型更改为unsigned short, 以获得最大值,或使用0x7FFF.

于 2013-04-11T11:49:17.837 回答
2
for (int i = 0; i < SIZE / sizeof(short); ++i) {
    ZBUFFER[i] = SHRT_MAX;
}

请注意,这不会初始化最后几个字节,if (SIZE % sizeof(short))

于 2013-04-11T11:58:50.250 回答
2

在 C 中,您可以像Adrian Panasiuk所说的那样做,也可以展开复制循环。展开意味着一次复制更大的块。循环展开的最末端是用零帧复制整个帧,如下所示:

init()
{
    for (int i = 0; i < sizeof(ZBUFFER) / sizeof(ZBUFFER[0]; ++i) {
        empty_ZBUFFER[i] = SHRT_MAX;
    }
}

实际清算:

memcpy(ZBUFFER, empty_ZBUFFER, SIZE);

(您可以试验不同大小的空 ZBUFFER,从 4 个字节及以上,然后围绕 memcpy 进行循环。)

与往常一样,测试您的发现,如果a)值得优化程序的这一部分,并且b)不同的初始化技术有什么不同。这将取决于很多因素。对于最后百分之几的性能,您可能不得不求助于汇编代码。

于 2013-04-11T13:34:11.440 回答
0
#include <algorithm>
#include <limits>

std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())

其中FOOZBUFFER's 元素的类型。

于 2013-04-11T12:01:39.023 回答
0

当您说“memset”时,您实际上必须使用该功能吗?这只是逐字节分配,因此不适用于签名数组。

如果要将每个值设置为最大值,则可以使用以下内容:

std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )

什么时候len是元素的数量(不是数组的字节大小)

于 2013-04-11T12:01:47.503 回答