1. 程式人生 > >糾正網上一篇關於c++ volatile關鍵字的文章中的疏漏

糾正網上一篇關於c++ volatile關鍵字的文章中的疏漏

    前幾天無意中看到一篇文章,闡述c++ volatile關鍵字的作用。仔細看下來覺得一處內容有待商榷,而文章也是博主轉載的,既然找不到原作者,只能在此指出了。

    首先,需要強調編譯器的版本,不同的編譯器有不同的優化方案,最終會影響生成的程式碼。本文使用vc++6.0(因為我猜測原作者用的也是vc++6.0),以下是示例程式碼:

#include <stdio.h>
 
void main()
{
	int i = 10;
	int a = i;
	
	printf("i = %d", a);

	// 下面彙編語句的作用就是改變記憶體中 i 的值
	// 但是又不讓編譯器知道
	__asm{
		mov dword ptr [ebp-4], 20h
	}
	 
	int b = i;
	printf("i = %d", b);
}

同時作者說在debug和release下,程式的輸出不同:

"   然後,在 Debug 版本模式執行程式,輸出結果如下:
i = 10
i = 32
    然後,在 Release 版本模式執行程式,輸出結果如下:
i = 10
i = 10"

作者把造成這種不同的原因歸結為:"而優化(指Release版)做法是,由於編譯器發現兩次從 i讀資料的程式碼之間的程式碼沒有對 i 進行過操作,它會自動把上次讀的資料放在 b 中。而不是重新從 i 裡面讀"。

    我不是很同意他的觀點:Release版,編譯器並沒有為變數a,b,i生成棧空間,而是直接用立即數0xa進行操作,因此無論作者怎麼操作[ebp-4],都不會影響最終輸出。以下是反彙編程式碼:

  00000	55		 push	 ebp
  00001	8b ec		 mov	 ebp, esp

; 5    : 	int i = 10;
; 6    : 	int a = i;
; 7    : 
; 8    : 	printf("i = %d", a);

  00003	6a 0a		 push	 10			; 0000000aH
  00005	68 00 00 00 00	 push	 OFFSET FLAT:[email protected][email protected][email protected] ; `string'
  0000a	e8 00 00 00 00	 call	 _printf

; 9    : 	__asm {
; 10   : 		mov dword ptr [ebp-4], 20h

  0000f	c7 45 fc 20 00
	00 00		 mov	 DWORD PTR [ebp-4], 32	; 00000020H

; 11   : 	}
; 12   : 	
; 13   : 	int b = i;
; 14   : 	printf("i = %d", b);

  00016	6a 0a		 push	 10			; 0000000aH
  00018	68 00 00 00 00	 push	 OFFSET FLAT:
[email protected]
[email protected][email protected] ; `string' 0001d e8 00 00 00 00 call _printf

  由於i的值在編譯前已經確定,並且在使用前也沒有發生不確定的變化(如接受使用者輸入等),因此編譯器認為printf的輸出引數可被優化為立即數。