原始的代碼來自:【MoreWindows工做筆記5】StrFormatByteSize64 高端大氣的顯示文件大小windows
可是代碼中有一個BUG,你看出什麼問題來了嗎?api
// 【MoreWindows工做筆記5】StrFormatByteSize64 高端大氣的顯示文件大小 #include <stdio.h> #include <math.h> #include <shlwapi.h> #pragma comment(lib, "shlwapi.lib") void NormFileSize(LONGLONG file_length, char* buffer, int buffer_size) { static double BASE_NUMBER = 1024.0; static char* SIZE_NAME[] = {"B","KB", "MB", "GB", "TB", "PB"}; double length = static_cast<double>(file_length); int i = 0; while (i < ARRAYSIZE(SIZE_NAME) && length > BASE_NUMBER) { length /= BASE_NUMBER; i++; } sprintf(buffer, "%lf %s", length, SIZE_NAME[i]); } int main() { printf(" 【MoreWindows工做筆記5】StrFormatByteSize64 高端大氣的顯示文件大小\n"); printf(" - http://blog.csdn.net/morewindows/article/details/16358955 -\n"); printf(" -- By MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n"); LONGLONG file_length = 34578; for (int i = 0; i < 10; i++) { printf("字節數 = %15I64d -- 文件大小:", file_length); char file_length_str1[100] = {0}; NormFileSize(file_length, file_length_str1, 100); printf("%15s ", file_length_str1); WCHAR file_length_str2[100] = {0}; StrFormatByteSizeW(file_length, file_length_str2, 100); // StrFormatByteSizeW會截斷尾數 printf("%ls\n", file_length_str2); // 還能夠試試StrFormatKBSize,這個只用KB來表示 file_length *= 11; } return 0; }
將9223372036854775807代入函數NormFileSize()
[文件爲testprintf.cpp]
數組
#include <windows.h> #include <stdio.h> #include <tchar.h> #include <stdio.h> #include <math.h> #include <shlwapi.h> #pragma comment(lib, "shlwapi.lib") void NormFileSize(LONGLONG file_length, char* buffer, int buffer_size) { static double BASE_NUMBER = 1024.0; char* SIZE_NAME[] = {"B","KB", "MB", "GB", "TB", "PB"}; double length = static_cast<double>(file_length); int i = 0; while (i < ARRAYSIZE(SIZE_NAME) && length > BASE_NUMBER) { length /= BASE_NUMBER; i++; } sprintf(buffer, "%lf %s", length, SIZE_NAME[i]); } int main() { printf(" 【MoreWindows工做筆記5】StrFormatByteSize64 高端大氣的顯示文件大小\n"); printf(" - http://blog.csdn.net/morewindows/article/details/16358955 -\n"); printf(" -- By MoreWindows( http://blog.csdn.net/MoreWindows ) --\n\n"); LONGLONG file_length = 34578; char file_length_str1[100] = {0}; WCHAR file_length_str2[100] = {0}; //for (int i = 0; i < 10; i++) //{ // printf("字節數 = %15I64d -- 文件大小:", file_length); // NormFileSize(file_length, file_length_str1, 100); // printf("%15s ", file_length_str1); // StrFormatByteSizeW(file_length, file_length_str2, 100); // StrFormatByteSizeW會截斷尾數 // printf("%ls\n", file_length_str2); // 還能夠試試StrFormatKBSize,這個只用KB來表示 // file_length *= 11; //} file_length=9223372036854775807; NormFileSize(file_length, file_length_str1, 100); return 0; }
接着咱們要來抓鬼--爲何會出現這個問題呢?
在下面所示的這個循環內,i值一直都是合法的,並且語義上徹底沒有問題,函數
while (i < ARRAYSIZE(SIZE_NAME) && length > BASE_NUMBER)
{
length /= BASE_NUMBER;
i++;
}.net
可是循環下面的代碼引用了這個變量,通常狀況下,不會有問題,而後有人在問---咱們必定要把沒問題的東西測出問題來嗎?可是若是在極端狀況下,好比代入很大的值,因而退出循環後i==ARRAYSIZE(SIZE_NAME),咱們知道,C++的數組const int MAX_INDEX=1000;int array[MAX_INDEX]下標範圍是0~MAX_INDEX-1,元素爲array[0],array[1],...array[MAX_INDEX-1],使用array[MAX_INDEX]就是越界!!!解決辦法就是在越界前結束循環:code
while (i < ARRAYSIZE(SIZE_NAME)-1 && length > BASE_NUMBER)
{
length /= BASE_NUMBER;
i++;
}
orm
#include <windows.h> #include <stdio.h> #include <tchar.h> TCHAR* Bytes2StringEx(const ULARGE_INTEGER ullSizeInBytes,TCHAR *lpszSizeInfo)//StrFormatByteSize64在ANSI工做不正常 { //from:MoreWindows <<StrFormatByteSize64 高端大氣的顯示文件大小>> //bytes //bytes/1024 kB //bytes/1024/1024 MB //bytes/1024/1024/1024 GB //bytes/1024/1024/1024/1024 TB long double FileSize= static_cast<long double>(ullSizeInBytes.QuadPart); long double BASE_NUMBER = 1024.0; TCHAR *UnitName[] = {TEXT("B"),TEXT("kB"), TEXT("MB"),TEXT("GB"), TEXT("TB"),TEXT("PB")}; int i = 0; int max_index=sizeof(UnitName)/sizeof(UnitName[0]) ; //int max_index2=ARRAYSIZE(UnitName); while ( i<max_index-1 && FileSize>1024.0 ) { FileSize /= 1024.0; i++; } TCHAR *un=UnitName[i];//雖然上面的while中i不會超出max_index可是,當超出時,下面引用到的正是超出的這個下標 #pragma warning(disable:4996) _sntprintf(lpszSizeInfo,10230, TEXT("%lf %s"),FileSize, un); return lpszSizeInfo; } TCHAR* Bytes2StringEx2(const ULARGE_INTEGER ullSizeInBytes,TCHAR *lpszSizeInfo)//StrFormatByteSize64在ANSI工做不正常 { //from:MoreWindows <<StrFormatByteSize64 高端大氣的顯示文件大小>> // http://blog.csdn.net/morewindows/article/details/16358955#comments // ulx.QuadPart=14757395258967641292;//代入這個天文數字,而後已經不是什麼PB //bytes //bytes/1024 kB //bytes/1024/1024 MB //bytes/1024/1024/1024 GB //bytes/1024/1024/1024/1024 TB long double FileSize= static_cast<long double>(ullSizeInBytes.QuadPart); TCHAR *StorageUnit[] = {TEXT("B"),TEXT("kB"), TEXT("MB"),TEXT("GB"),TEXT("TB"),TEXT("PB"),TEXT("EB"),TEXT("ZB"),TEXT("YB"),TEXT("BB"),TEXT("NB"),TEXT("DB")}; const int UNIT_MAX_INDEX=sizeof(StorageUnit)/sizeof(StorageUnit[0]); const long double BASE_NUMBER = 1024.0; int i = 0; while ( i<UNIT_MAX_INDEX-1 && FileSize>BASE_NUMBER )//bug fixed:雖然上面的while中i不會超出UNIT_MAX_INDEX可是,當超出時,下面引用到的正是超出的這個下標因此要減一:i<UNIT_MAX_INDEX-1 { FileSize /=BASE_NUMBER; i++; } #pragma warning(disable:4996) _stprintf(lpszSizeInfo,TEXT("%lf%s"),FileSize, StorageUnit[i]); return lpszSizeInfo; } int _tmain() { ULARGE_INTEGER ulx; ulx.QuadPart=-1;//(unsigned long long)-1==18446744073709551615,0xcccccccccccccccc=14757395258967641292;//代入這個天文數字,而後已經不是什麼PB TCHAR lpszSizeInfo[20]; _tprintf(TEXT("%I64u bytes"),ulx.QuadPart ); Bytes2StringEx(ulx,lpszSizeInfo); _tprintf(TEXT("=%s "),lpszSizeInfo); Bytes2StringEx2(ulx,lpszSizeInfo); _tprintf(TEXT("=%s\n"),lpszSizeInfo); getchar();//pause return 0; }