C語言extern引用AT&T彙編中的變量,任意轉換類型

今天研究出了一個小問題,在C語言裏引用匯編的變量,會是什麼結果,彙編中的變量沒有像C語言中int類型那樣的類型約束,可以把數據當作任何類型處理,那麼傳到C語言中我們應該當作什麼類型處理呢。

換句話說,在彙編裏定義變量var,在C語言裏引用,我們肯定要用extern聲明var外部變量,那麼extern後面接什麼類型?難道是extern int var麼?還是 extern short var


實例:

注意:混合編譯的方法,gcc test.s main.c 這樣直接用gcc處理彙編和C語言文件就可以自動搞定。

一、

彙編程序:(是的,就這麼短小)

.global var  #注意現在的彙編器不再要求被C語言引用的變量名前加下劃線
.data
var:
	.fill 10,4,9 #填充10個單元,每個單元4字節,每個單元的值爲9

C語言:

#include <stdio.h> 
extern int var;  //現在的C語言編譯器引用匯編變量可以使用和彙編變量同樣的名字,寫成_var反而會錯誤
void main() 
{ 
	printf("sizeof(var)=%d\n",sizeof(var));
	printf("%d\n", var); 
}

程序的輸出爲

sizeof(int)=4
9

解釋很簡單,

wKioL1UyThyhEVK1AABn_JIymqM381.jpg

如上圖,我只畫了四個字節,我填充了10個單元的,每單元佔用4字節,意思就是每個9佔四個字節。如圖,然後C語言裏聲明爲extern int var;就是把前四個字節看作一個int變量取出來,當然是9了。

二、

保持C語言程序和上一個一樣,

extern int var;

把彙編語句改成

.fill 10,2,9 #10個單元,每個單元填入9,每單元大小爲2B

這就意味着每個單元2字節,每個單元填一個9,我們不改變C語言語句,那麼仍將把var看作int型4字節變量,依然是一次取出前4個字節作爲var的值。那我們推測一下結果會是什麼。

首先每個9佔用兩字節,內存圖應該是這樣的,(只畫了4字節,後面沒畫)

wKioL1UyTtjCtjvIAABkoAsAul4794.jpg

一次性取出4個字節,就是0x00090009,這玩意兒拿到windows自帶計算器裏算出來是是十進制的589833,這就是我們的預測值。讓我們看下程序結果是不是和我們猜的一樣。

wKioL1UyT76zt-bEAABmJmoXbCM037.jpg


沒錯吧,這就是說我們在彙編裏定義的變量,來到C語言裏可以任意聲明爲任意類型,從sizeof的輸出也能看出,我們把var聲明成多大,它就是多大。

三、

我們再試試別的,彙編語句保持和上一個一樣,依然是

.fill 10,2,9 #10個單元,每個單元填入9,每單元大小爲2B

我們改變C語言語句,把var聲明成

extern long long var; //8字節整型

當然,輸出語句稍微變下,因爲是long long型整數,所以要這麼輸出printf("%lld\n", var);

#include <stdio.h> 
extern long long var;   
void main() 
{ 
	printf("sizeof(var)=%d\n",sizeof(var));
	printf("%lld\n", var); 
}

我們還是事先猜測結果,字節太多我不畫圖了,按照上面的的思路,這次取出8字節當作long long變量var的值,那麼應該是0x0009000900090009,化爲十進制是2533313445691401。

看看程序運行結果:

wKiom1UyUK_jBcMdAABNgTifnuA454.jpg

預測正確。

四、

再來,把var聲明爲char變量。

#include <stdio.h> 
extern char var;   #聲明爲char
void main() 
{ 
	printf("sizeof(var)=%d\n",sizeof(var));
	printf("%c\n", var); 
}

輸出語句相應的改變成%c

彙編裏面稍微改改填充的數值,因爲9是製表符的ASCII碼,輸出了你也看不到。我們改成填充43

.fill 10,2,43 #10個單元,每個單元填入43(內存實際存儲按照二進制來的),每單元大小爲2B

注意43的十六進制表示爲0x2b,這是加號“+”的ASCII碼,

內存裏面長成這樣

wKioL1UyVFeRALi9AABqDKISKjM708.jpg

C語言會認爲var是char型的,取出一個字節當作var的值,也就是把0x2b送給var,我們把var用%c輸出,就是輸出了0x2b這個ASCII碼所代表的字符。就是“+”號。

wKioL1UyVPTxY4n6AAA1Qy3PZAc866.jpg


五、

好吧,再這麼整下去也沒完了,下面用一個數組定義來終結此文吧。

彙編語言代碼和上一個一樣,

.fill 10,2,43

C語言修改成:

#include <stdio.h> 
typedef char CHARARR[20]; //CHARARR是一個類型別名,用它定義的每一個變量都是包含20個字符的數組
extern CHARARR var; //var被定義爲CHARARR類型,是一個包含20個元素的char型數組。
void main() 
{ 
	printf("sizeof(var)=%d\n",sizeof(var));
	int i=0;
	while(i<=19)
	{
		printf("[%c]", var[i]); //用[]括起來更容易看出輸出現象
		i++;
	}
	printf("\n");
}

我們讓var成爲數組,含有20個元素,正好把彙編裏面的 10單元x2字節 共計20個字節包括了。

然後用循環逐個輸出,爲什麼要這麼做而不用%s呢,因爲數組裏有很多字節是0x00,這是字符串終止標誌。%s會被打斷的。

結果如下:

wKiom1UyWXKiWre3AABj5Z9H3Ec038.jpg

可以看到和預計的一樣,20個元素以ASCII碼 0x2b 0x00 0x2b 0x00。。。。這樣的數組順序挨個輸出。


講完了,C語言和彙編語言結合起來是不是強大到了難以想象的地步,隨心所欲操縱內存數據。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章