似乎无法在任何地方找到答案,
如何将数组memset到数组类型的最大值?
我原以为memset(ZBUFFER,0xFFFF,size)
可以在ZBUFFER是16位整数数组的情况下工作。相反,我得到-1s。
此外,我们的想法是尽可能快地完成这项工作(这是一个需要初始化每一帧的zbuffer),所以如果有更好的方法(并且仍然快速或更快),请告诉我。
编辑: 作为澄清,我确实需要一个有符号的int数组。
答案 0 :(得分: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
循环。
答案 1 :(得分:7)
-1和0xFFFF是相同的。您只获得-1,因为您已将数组声明为short
而不是unsigned short
。或者因为您在输出值时将值转换为signed。
顺便说一句你的假设你可以使用memset设置除 bytes 之外的东西是错误的。 memset(ZBUFFER, 0xFF, size)
会做同样的事情。
答案 2 :(得分:4)
在C ++中,您可以使用std::fill
算法为数组填充一些值。
std::fill(ZBUFFER, ZBUFFER+size, std::numeric_limits<short>::max());
这既不比你现在的方法更快也不慢。但它确实有工作的好处。
答案 3 :(得分: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选项。以下是the memset manual的引用:
memset()函数将c(转换为 unsigned char )复制到 s指向的对象的前n个字节中的每一个。
因此,它会将0xFFFF转换为unsigned char(并可能截断该值),然后将转换后的值分配给第一个size
字节。这会导致不正确的行为。我不喜欢依赖值SHRT_MAX来表示存储值(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.
这些测试可能会有所不同,但显着。我每次只运行一次以获得一个粗略的想法。希望你得出的结论与我相同:常见的编译器非常擅长优化简单循环,并且不值得在此处假设微优化。
总结:
答案 4 :(得分:2)
这是因为two's complement。您必须将数组类型更改为unsigned short
,以获取最大值,或使用0x7FFF
。
答案 5 :(得分:2)
for (int i = 0; i < SIZE / sizeof(short); ++i) {
ZBUFFER[i] = SHRT_MAX;
}
请注意,这不会初始化最后几个字节if (SIZE % sizeof(short))
答案 6 :(得分: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,从四个字节开始,然后围绕memcpy循环。)
与往常一样,测试您的发现,如果 a)值得优化程序的这一部分, b)不同的初始化技术会有什么不同。这取决于很多因素。对于性能的最后几分钟,您可能不得不求助于汇编程序代码。
答案 7 :(得分:0)
#include <algorithm>
#include <limits>
std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())
其中FOO
是ZBUFFER
元素的类型。
答案 8 :(得分:0)
当你说“memset”时你真的必须使用那个功能吗?这只是一个逐字节的分配,所以它不适用于有符号数组。
如果要将每个值设置为最大值,可以使用以下内容:
std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )
当len
是元素的数量(不是数组的字节大小)时