[英]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.