今天參加了CSDN的英雄會,有幸見了些名人,回到家上CSDN,看到個帖子
http://topic.csdn.net/u/20080905/16/3823c75d-c33b-4ea0-83b1-8386d03e6c6c.html
具體內容:
題目:
1、不能用庫函數,要求達到效率o(1);
2、將符號'@'插入字符串ptr的首位,字符串ptr原內容按照原來的順序排在'@'之後.
{
//填寫代碼:
}
void main(void)
{
char ptr[16]="abcdefg";
char temp='@';
insert(ptr, temp);
printf("%s/n;",ptr);
}
我很容易想到
{
*((__int64*)(str + 1)) = *(__int64*)str;
*str = tmp;
}
可是結果卻很令人驚訝,輸出@abcddfg,有一個字節不對。仔細一想,應該是把64位變量放到2個寄存器中了。
用OD反一下,看下主函數裏的關鍵地方,OH,前面分配棧的一句是sub esp,18
200401035 |? 8945 EC mov dword ptr [ebp-14], eax
300401038 |? 8B0D E0B64000 mov ecx, dword ptr [40B6E0]
40040103E |? 894D F0 mov dword ptr [ebp-10], ecx
500401041 |? 33D2 xor edx, edx ; namespac.0040E2B8
600401043 |? 8955 F4 mov dword ptr [ebp-C], edx
700401046 |? 8955 F8 mov dword ptr [ebp-8], edx
800401049 |? C645 EB 40 mov byte ptr [ebp-15], 40
90040104D |? 0FB645 EB movzx eax, byte ptr [ebp-15]
1000401051 |. 50 push eax
1100401052 |? 8D4D EC lea ecx, dword ptr [ebp-14]
1200401055 |? 51 push ecx
1300401056 |. E8 A5FFFFFF call 00401000
140040105B |? 83C4 08 add esp, 8
200401001 |. 8BEC mov ebp, esp
300401003 |. 8B45 08 mov eax, dword ptr [ebp+8]
400401006 |. 8B4D 08 mov ecx, dword ptr [ebp+8]
500401009 |? 8B11 mov edx, dword ptr [ecx]
60040100B |. 8950 01 mov dword ptr [eax+1], edx
70040100E |? 8B49 04 mov ecx, dword ptr [ecx+4]
800401011 |? 8948 05 mov dword ptr [eax+5], ecx
900401014 |? 8B55 08 mov edx, dword ptr [ebp+8]
1000401017 |. 8A45 0C mov al, byte ptr [ebp+C]
110040101A |. 8802 mov byte ptr [edx], al
120040101C |? 5D pop ebp
130040101D |. C3 retn
第5行把char ptr[16]的前4個字節abcd存入edx,也就是0x64636261,注意高低位
然後把edx裏的4個字節的數,寫入ptr+1的位置,可見問題就出現在這裏,一下寫入4個字節,在ptr+1到ptr+4的位置,由於*(ptr+4)裏的內容並未保存,所以被覆蓋了,導致後面第2次讀取的數據不正確,最後的結果也不會輸出正確
看了下邊網友的回帖,比較好的方法就是用移位,本來是數,移位肯定不會出問題,使用的是shld雙精度左移指令(爲什麼是左移不是右移?同樣注意高低位),保證數據不會丟失
{
*(__int64*)str <<= 8;
*str = tmp;
}
可以看出,在32位系統使用64位變量需要很注意,尤其是在賦值的時候,比如我上邊的例子。往往在一個大工程裏,出現這樣的問題,很難查出原因來,因此,需要格外注意。還有在多線程的時候,一個讀一個寫,由於使用2個寄存器,就有可能在一個寫線程操作到一個64位數的32位的時候,線程正好切換到讀線程,導致產生一些奇怪的數據,而且這種奇怪的情況並不是每次運行都能體現出來,造成的損失可想而知。所以對跨線程使用64位變量必須嚴格進行同步。
by greatws