似乎无法在任何地方找到答案,如何将数组设置为数组类型的最大值?我原以为memset(ZBUFFER,0xFFFF,size)
ZBUFFER 是一个 16 位整数数组的地方会起作用。相反,我始终得到-1。
此外,我们的想法是尽可能快地完成这项工作(它是一个需要初始化每一帧的 zbuffer),所以如果有更好的方法(并且仍然一样快或更快),请告诉我。
编辑:作为澄清,我确实需要一个带符号的 int 数组。
在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
循环。
-1 和 0xFFFF 在使用二进制补码表示的 16 位整数中是相同的。您只得到 -1 是因为您已将数组声明为short
而不是unsigned short
. 或者因为您在输出它们时将值转换为有符号。
顺便说一句,您假设您可以使用 memset设置字节以外的内容是错误的。memset(ZBUFFER, 0xFF, size)
会做同样的事情。
在 C++ 中,您可以使用算法为数组填充一些值std::fill
。
std::fill(ZBUFFER, ZBUFFER+size, std::numeric_limits<short>::max());
这既不比您当前的方法快也不慢。不过,它确实有工作的好处。
不要将速度归因于语言。那是为了 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.
这些测试可能会有所不同,但差异很大。我每个人只运行一次以获得一个粗略的想法。希望您得出与我相同的结论:普通编译器非常擅长优化简单循环,因此不值得在这里假设微优化。
总之:
这是因为补码。您必须将数组类型更改为unsigned short
, 以获得最大值,或使用0x7FFF
.
for (int i = 0; i < SIZE / sizeof(short); ++i) {
ZBUFFER[i] = SHRT_MAX;
}
请注意,这不会初始化最后几个字节,if (SIZE % sizeof(short))
在 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)不同的初始化技术有什么不同。这将取决于很多因素。对于最后百分之几的性能,您可能不得不求助于汇编代码。
#include <algorithm>
#include <limits>
std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())
其中FOO
是ZBUFFER
's 元素的类型。
当您说“memset”时,您实际上必须使用该功能吗?这只是逐字节分配,因此不适用于签名数组。
如果要将每个值设置为最大值,则可以使用以下内容:
std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )
什么时候len
是元素的数量(不是数组的字节大小)