[英]Memset an int (16 bit) array to short's max value
似乎在任何地方都找不到答案,如何将数组设置为数组类型的最大值? 我以为memset(ZBUFFER,0xFFFF,size)
在ZBUFFER是16位整数数组的情况下会起作用。 相反,我得到-1s。
另外,我们的想法是使这项工作尽可能快(这是一个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(转换为无符号char )复制到s所指向的对象的前n个字节中的每个字节中。
因此,它将0xFFFF转换为无符号字符(并可能截断该值),然后将转换后的值分配给第一个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)
倍。 考虑到我的实现使用了相当理想的内存集,下面是输出:
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,然后在memcpy周围进行循环。)
和往常一样,测试您的发现,如果a)值得优化程序的这一部分, b)不同的初始化技术有什么不同。 这将取决于很多因素。 对于最后百分之几的性能,您可能不得不求助于汇编代码。
#include <algorithm>
#include <limits>
std::fill_n(ZBUFFER, size, std::numeric_limits<FOO>::max())
其中FOO
是ZBUFFER
元素的类型。
当您说“ memset”时,您实际上必须使用该功能吗? 那只是一个字节一个字节的分配,因此它不适用于带符号数组。
如果您想将每个值设置为最大值,则可以使用以下方法:
std::fill( ZBUFFER, ZBUFFER+len, std::numeric_limits<short>::max() )
当len
是元素数(而不是数组的字节大小)时
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.