最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C語言深入分析整形數(shù)據(jù)存儲

 更新時(shí)間:2022年08月12日 16:43:37   作者:進(jìn)擊的安度因  
C語言中,我們經(jīng)常使用數(shù)據(jù)類型,那么整形數(shù)據(jù)在內(nèi)存中如何存儲?存儲方式是什么?如果你對這些內(nèi)容不太了解的話,相信看完這篇博客后,你會對整形數(shù)據(jù)的存儲有一個(gè)新的認(rèn)識。話不多說,我們進(jìn)入正題

數(shù)據(jù)類型

C語言中存在著數(shù)據(jù)類型,我們或多或少都見到過。

char //字符數(shù)據(jù)類型 - 1個(gè)字節(jié)

short //短整型 - 2個(gè)字節(jié)

int //整形 - 4個(gè)字節(jié)

long //長整型 - 4/8個(gè)字節(jié)

long long //更長的整形 - 8個(gè)字節(jié)

float //單精度浮點(diǎn)數(shù) - 4個(gè)字節(jié)

double //雙精度浮點(diǎn)數(shù) - 8個(gè)字節(jié)

小思考:C語言有沒有字符串類型?

C語言有字符串,表示為"字符串內(nèi)容"的形式,但不存在字符串類型。

類型存在的意義是什么?

  • 使用這個(gè)類型開辟內(nèi)存空間的大小(大小決定使用范圍)。
  • 如何看待內(nèi)存空間的視角(例如指針解引用和指針運(yùn)算)。

類型的分類

整形

char
    unsigned char
    signed char
//雖然是字符類型,但是字符類型存儲的時(shí)候,存儲的字符的ascii碼值,ascii碼值是整數(shù)
short
    unsigned short [int]
    signed short [int]
int
    unsigned int
    signed int
long
    unsigned long [int]
    signed long [int]

unsigned 和 signed

  • unsigned:無符號,只有正數(shù)的數(shù)據(jù)可以存放在無符號的變量中。
  • signed:有符號,有正負(fù)的數(shù)據(jù)可以存放在有符號的變量中。

Tips:

對于short,int,long,long long數(shù)據(jù)在進(jìn)行定義時(shí),默認(rèn)都為signed。而對于char類型則不確定,C語言標(biāo)準(zhǔn)沒有規(guī)定char是否有符號,取決于編譯器,所以char實(shí)際上可以歸為3類,char(不確定),signed char(有符號),unsigned char(無符號)。在vs2022中,char默認(rèn)為signed char。

浮點(diǎn)型

float//單精度浮點(diǎn)數(shù) - 4個(gè)字節(jié)
double//雙精度浮點(diǎn)數(shù) - 8個(gè)字節(jié)

構(gòu)造類型

//例:int arr[10]
數(shù)組類型 int [10]
//數(shù)組只要個(gè)數(shù)和元素類型發(fā)生變化,類型都會發(fā)生變化
結(jié)構(gòu)體類型 struct
枚舉類型 enum
聯(lián)合類型 union

指針類型

int *pi;//整形指針
char *pc;//字符指針
float* pf;//單精度浮點(diǎn)數(shù)指針
void* pv;//空類型指針

空類型

void 表示空類型(無類型)

通常應(yīng)用于函數(shù)的返回類型、函數(shù)的參數(shù)、指針類型。

例:

void test1()//無返回值
{}
void test2(void)//函數(shù)接收參數(shù),參數(shù)部分加void
{}
int main()
{
	void* p = NULL;
	//void*可以存放任何類型的指針
	int a = 10;
	void* p1 = &a;//沒問題
	p1++;//err,不知道類型,無法決定跳過幾個(gè)字節(jié)
	*p1;//err,不知道類型,無法決定解引用的權(quán)限
	//一般用來臨時(shí)存放地址,用的時(shí)候拿走或者強(qiáng)轉(zhuǎn)使用
	return 0;
}

整形在內(nèi)存中的存儲

一個(gè)整形變量的創(chuàng)建需要再內(nèi)存中開辟四個(gè)字節(jié),那整形在內(nèi)存中是如何存儲的?

比如:

int a = 10;

int b = -10;

在了解整形在內(nèi)存中如何存儲之前我們需要了解以下概念:

原碼、反碼、補(bǔ)碼

計(jì)算機(jī)中的整數(shù)有三種2進(jìn)制表示方法,即原碼、反碼、補(bǔ)碼。

三種表示方法均有符號位和數(shù)值位兩部分,二進(jìn)制序列的第一位為符號位,其他均為數(shù)值位,符號位數(shù)值位均由0,1組成。

原碼:

直接將數(shù)值按照正負(fù)的形式翻譯成二進(jìn)制就可以。

反碼:

原碼的符號位不便,其他位依次按位取反就可以得到。

補(bǔ)碼:

反碼 + 1得到補(bǔ)碼。

注意:

  • 正整數(shù)的原碼、反碼、補(bǔ)碼都相同。
  • 負(fù)整數(shù)的三種表示方式各不相同,需要通過計(jì)算得到。

樣例:

int a = 10;//整形值
//0000 0000 0000 0000 0000 0000 0000 1010 a的原、反、補(bǔ)
//轉(zhuǎn)化為16進(jìn)制:0X0000000a
int b = -10;//整形值
//1000 0000 0000 0000 0000 0000 0000 1010 b的原碼
//1111 1111 1111 1111 1111 1111 1111 0101 b的反碼
//1111 1111 1111 1111 1111 1111 1111 0110 b的補(bǔ)碼
//轉(zhuǎn)化為16進(jìn)制:0Xfffffff6

那么對于整形而言,在內(nèi)存中存儲的是什么呢?

讓我們啟動(dòng)調(diào)試,查看內(nèi)存:

我們可以看到對于a和b分別存儲的是補(bǔ)碼,這是為什么?

在計(jì)算機(jī)系統(tǒng)中,數(shù)值一律用補(bǔ)碼來表示和存儲。原因在于,使用補(bǔ)碼,可以將符號位和數(shù)值域統(tǒng)一處理;

同時(shí),加法和減法也可以統(tǒng)一處理(CPU只有加法器)此外,補(bǔ)碼與原碼相互轉(zhuǎn)換,其運(yùn)算過程是相同的,不需要額外的硬件電路。

舉個(gè)簡單的例子,例如計(jì)算機(jī)在計(jì)算a - b的時(shí)候,會轉(zhuǎn)化成a + (-b)的形式進(jìn)行計(jì)算,而這時(shí)使用原碼來進(jìn)行計(jì)算,是無法計(jì)算出結(jié)果的,但使用補(bǔ)碼就可以計(jì)算出結(jié)果。

但是對于數(shù)據(jù)在內(nèi)存中存儲的方式很奇怪,它是倒著存儲的,這是為什么?讓我們了解一下大小端。

大小端介紹

什么是大端小端:

大端字節(jié)序存儲:把一個(gè)數(shù)據(jù)低位字節(jié)處的數(shù)據(jù)存放在高地址處,把高位字節(jié)處的數(shù)據(jù)放在低地址處

小端字節(jié)序存儲:把一個(gè)數(shù)據(jù)低位字節(jié)處的數(shù)據(jù)存放在低地址處,把高位字節(jié)處的數(shù)據(jù)放在高地址處。

例如:

0x11223344

為什么會有大端和小端:

為什么會有大小端模式之分呢?這是因?yàn)樵谟?jì)算機(jī)系統(tǒng)中,我們是以字節(jié)為單位的,每個(gè)地址單元都對應(yīng)著一個(gè)字節(jié),一個(gè)字節(jié)為8 bit。但是在C語言中除了8 bit的char之外,還有16 bit的short型,32 bit的long型(要看具體的編譯器),另外,對于位數(shù)大于8位的處理器,例如16位或者32位的處理器,由于寄存器寬度大于一個(gè)字節(jié),那么必然存在著一個(gè)如何將多個(gè)字節(jié)安排的問題。因此就導(dǎo)致了大端存儲模式和小端存儲模式。

例如:一個(gè)16bit 的short 型x ,在內(nèi)存中的地址為0x0010 , x 的值為0x1122 ,那么0x11 為高字節(jié), 0x22 為低字節(jié)。對于大端模式,就將0x11 放在低地址中,即0x0010 中, 0x22 放在高地址中,即0x0011 中。小端模式,剛好相反。我們常用的X86 結(jié)構(gòu)是小端模式,而KEIL C51 則為大端模式。很多的ARM,DSP都為小端模式。有些ARM處理器還可以由硬件來選擇是大端模式還是小端模式。

其實(shí)數(shù)據(jù)在內(nèi)存中無論是大小端存儲或者亂序存儲都可以,大小端字節(jié)序存儲也是為了讓存儲方式變得更簡單,如果亂序存儲的話在還原數(shù)據(jù)時(shí)會更加復(fù)雜。

注:大小端存儲時(shí)以字節(jié)為單元,16進(jìn)制的兩位為一個(gè)字節(jié),為一個(gè)單元,按照大小端存儲規(guī)律存儲,并不會將16進(jìn)制的每一位都倒過來存儲。例如0x123456按照小端存儲就為56 34 12 00,而不是65 43 21 00。

所以說大小端字節(jié)序存儲,就是以字節(jié)為單位的存儲順序。

一道筆試題

請簡述大端字節(jié)序和小端字節(jié)序的概念,設(shè)計(jì)一個(gè)小程序來判斷當(dāng)前機(jī)器的字節(jié)序。

思路:數(shù)據(jù)在內(nèi)存中是通過補(bǔ)碼的形式儲存的,判斷大端還是小端,例如數(shù)字1,我們只需要觀察它的第一個(gè)字節(jié)為0或1,就可以判斷字節(jié)序。而數(shù)據(jù)類型決定了指針解引用時(shí)看待內(nèi)存的視角,所以我們可以用char*指針來對元素第一個(gè)字節(jié)的內(nèi)容進(jìn)行解引用。

int check_sys()
{
	int a = 1;
	//二進(jìn)制:0000 0000 0000 0000 0000 0000 0000 0001
	//十六進(jìn)制:0x00000001
	char* p = (char*)&a;//char*指針解引用為一個(gè)字節(jié)
	if (*p == 1)
		return 1;
	else
		return 0;
}
//簡化
//int check_sys()
//{
//	int a = 1;
//	return *(char*)&a;//1的大端或小端存儲,第一位為00或者01,取出的值正好和main函數(shù)中接收的值相同,直接返回
//}
int main()
{
	int ret = check_sys();
	if (ret = 1)
	{
		printf("小端\n");
	}
	else
	{
		printf("大端\n");
	}
}

char類型數(shù)據(jù)的取值范圍

char在內(nèi)存中存儲的是字符的Ascii碼值,所以也歸于整形。但是它的取值范圍和整形不同。

char類型變量的大小為1個(gè)byte,也就是8個(gè)bit位,對于char類型,我們分signed和unsigned兩塊進(jìn)行講解。

signed:

signed為有符號字符類型,二進(jìn)制序列的第一位為符號位,其他位為數(shù)據(jù)位,取值范圍為-128 ~ 127.

unsigned:

unsigned為無符號字符類型,二進(jìn)制序列全為數(shù)據(jù)位,取值范圍為0 ~ 255.

圖例:

練習(xí)

練習(xí)1

下列程序的輸出結(jié)果是什么?

int main()
{
	char a = -1;
	//整形提升
    //1000 0000 0000 0000 0000 0000 0000 0001
	//1111 1111 1111 1111 1111 1111 1111 1110
	//1111 1111 1111 1111 1111 1111 1111 1111
    //截?cái)啵?111 1111
    //整形提升
	//1111 1111 1111 1111 1111 1111 1111 1111 - 補(bǔ)碼
	//1000 0000 0000 0000 0000 0000 0000 0000
	//1000 0000 0000 0000 0000 0000 0000 0000 - 原碼
    //-1
	signed char b = -1;
	//求解過程和a相同
	unsigned char c = -1;
	//截?cái)啵?111 1111
    //無符號字符,整形提升,高位補(bǔ)0
    //0000 0000 0000 0000 0000 0000 1111 1111 - 補(bǔ)碼==原碼
    //截?cái)啵?111 1111
	printf("a=%d,b=%d,c=%d", a, b, c);//-1,-1,255
	//當(dāng)打印a,b,c時(shí),要整形提升
	return 0;
}

運(yùn)行結(jié)果:

練習(xí) 2

下列程序的輸出結(jié)果是什么?

int main()
{
	char a = -128;
	//1000 0000 0000 0000 0000 0000 1000 0000
	//1111 1111 1111 1111 1111 1111 0111 1111
	//1111 1111 1111 1111 1111 1111 1000 0000
	//截?cái)啵?000 0000
	//%u - 指的是打印無符號整數(shù)
	//整形提升
    //有符號字符,補(bǔ)符號位
	//1111 1111 1111 1111 1111 1111 1000 0000 - 要打印原碼,而這是無符號數(shù),所以這個(gè)就是原碼
	printf("%u\n", a);//4294967168
	return 0;
}

運(yùn)行結(jié)果:

練習(xí) 3

下列程序的輸出結(jié)果是什么?

int main()
{
	char a = 128;
	//0000 0000 0000 0000 0000 0000 1000 0000
	//1111 1111 1111 1111 1111 1111 0111 1111
	//1111 1111 1111 1111 1111 1111 1000 0000
	//截?cái)?000 0000
	//整形提升
    //有符號字符,補(bǔ)符號位
	//1111 1111 1111 1111 1111 1111 1000 0000 - 原碼
	printf("%u\n", a);//?
	return 0;
}

運(yùn)行結(jié)果:

練習(xí) 4

下列程序的輸出結(jié)果是什么?

int main()
{
	int i = -20;
	//1000 0000 0000 0000 0000 0000 0001 0100 - 原碼
	//1111 1111 1111 1111 1111 1111 1110 1011 - 反碼
	//1111 1111 1111 1111 1111 1111 1110 1100 - 補(bǔ)碼
	unsigned int j = 10;
	//0000 0000 0000 0000 0000 0000 0000 1010 - 補(bǔ)碼
	printf("%d\n", i + j);//-10
	//i + j
	//1111 1111 1111 1111 1111 1111 1111 0110 - 補(bǔ)碼
    //打印有符號整形,轉(zhuǎn)化成原碼
	//1000 0000 0000 0000 0000 0000 0000 1001
	//1000 0000 0000 0000 0000 0000 0000 1010 - 原碼
	return 0;
}

運(yùn)行結(jié)果:

練習(xí) 5

下列程序的輸出結(jié)果是什么?

int main()
{
	unsigned int i;//恒大于0
	for (i = 9; i >= 0; i--)//死循環(huán)
	{
		printf("%u\n", i);
        //9 ~ 0 ~ 超大的值:-1的補(bǔ)碼組成的循環(huán)
		//-1的補(bǔ)碼:1111 1111 1111 1111 1111 1111 1111 1111
        //放到無符號整數(shù)中,將-1的補(bǔ)碼直接當(dāng)做原碼輸出
        //得到超大的值
        Sleep(1000);//程序停止一秒
	}
	return 0;
}

運(yùn)行結(jié)果:

練習(xí) 6

下列程序的輸出結(jié)果是什么?

int main()
{
	char a[1000];
	int i;
	for (i = 0; i < 1000; i++)
	{
		a[i] = -1 - i;
        //char取值范圍-128 ~ 127
        //當(dāng)a[i]的值小于-128時(shí),會轉(zhuǎn)化成127并大于0的值,當(dāng)a[i]=0時(shí),
        //'\0'的ascii碼值為0,當(dāng)strlen進(jìn)行計(jì)算時(shí),計(jì)算第一個(gè)'\0'前的字符個(gè)數(shù)
		//數(shù)組中元素:-1 , -2 , ... ,-128 , 127, ..., 1, 0...
	}
	printf("%d", strlen(a));
	//求'\0'前字符的個(gè)數(shù)
    //'\0'的ascii碼值為0
}

圖解:

運(yùn)行結(jié)果:

練習(xí) 7

下列程序的輸出結(jié)果是什么?

unsigned char i = 0;//0 ~ 255
int main()
{
    int i = 0;
    //0 ~ 255為區(qū)間,循環(huán)進(jìn)行這個(gè)區(qū)間,打印hello world
	for (i = 0; i <= 255; i++)//死循環(huán)
	{
		printf("hello worrld\n");
	}
}

運(yùn)行結(jié)果:

到此這篇關(guān)于C語言深入分析整形數(shù)據(jù)存儲的文章就介紹到這了,更多相關(guān)C語言數(shù)據(jù)存儲內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • C++快速排序及優(yōu)化方案詳解

    C++快速排序及優(yōu)化方案詳解

    這篇文章主要介紹了C++快速排序及優(yōu)化方案詳解,快速排序是一種常用的排序算法,它通過選擇一個(gè)基準(zhǔn)元素,將數(shù)組分成兩個(gè)子數(shù)組,其中一個(gè)子數(shù)組的所有元素都小于基準(zhǔn)元素,另一個(gè)子數(shù)組的所有元素都大于基準(zhǔn)元素,需要的朋友可以參考下
    2023-10-10
  • Qt快速讀取大文件最后一行內(nèi)容解決方案

    Qt快速讀取大文件最后一行內(nèi)容解決方案

    這篇文章主要給大家介紹了關(guān)于Qt如何快速讀取大文件最后一行內(nèi)容的解決方案,文中通過代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Qt具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2024-01-01
  • C語言實(shí)現(xiàn)打印星號圖案

    C語言實(shí)現(xiàn)打印星號圖案

    這篇文章主要介紹了C語言實(shí)現(xiàn)打印星號圖案,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • C++利用SQLite實(shí)現(xiàn)命令行工具

    C++利用SQLite實(shí)現(xiàn)命令行工具

    這篇文章主要為大家詳細(xì)介紹了一個(gè)基于 C++、SQLite 和 Boost 庫的簡單交互式數(shù)據(jù)庫操作 Shell,該 Shell 允許用戶通過命令行輸入執(zhí)行各種數(shù)據(jù)庫操作,感興趣的可以了解下
    2023-11-11
  • C++實(shí)現(xiàn)LeetCode(22.生成括號)

    C++實(shí)現(xiàn)LeetCode(22.生成括號)

    這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(22.生成括號),本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-07-07
  • C++?使用getline()從文件中讀取一行字符串方法示例

    C++?使用getline()從文件中讀取一行字符串方法示例

    這篇文章主要介紹了C++?使用getline()從文件中讀取一行字符串方法示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-09-09
  • 五個(gè)嵌入式C語言中的實(shí)用技巧分享

    五個(gè)嵌入式C語言中的實(shí)用技巧分享

    這篇文章主要和大家分享一下五個(gè)嵌入式C語言中的實(shí)用技巧,文中的示例代碼講解詳細(xì),對我們學(xué)習(xí)C語言有一定的幫助,需要的可以參考一下
    2022-12-12
  • Microsoft Visual C++ 安裝失敗 0x80070666的問題解決

    Microsoft Visual C++ 安裝失敗 0x80070666的問題解

    本文主要介紹了Microsoft Visual C++ 安裝失敗 0x80070666的問題解決,錯(cuò)誤可能由已安裝其他VisualC++版本、VisualC++安裝異常、Windows更新計(jì)劃安裝同一VisualC++包等原因引起,下面就來介紹一下解決方案,感興趣的可以了解一下
    2025-03-03
  • C++:構(gòu)造函數(shù),析構(gòu)函數(shù)詳解

    C++:構(gòu)造函數(shù),析構(gòu)函數(shù)詳解

    今天小編就為大家分享一篇關(guān)于C++構(gòu)造函數(shù)和析構(gòu)函數(shù)的文章,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2021-09-09
  • 基于C語言實(shí)現(xiàn)UDP服務(wù)器

    基于C語言實(shí)現(xiàn)UDP服務(wù)器

    這篇文章主要為大家詳細(xì)介紹了如何使用C語言編寫一個(gè)簡單的UDP服務(wù)器程序,以及如何接收和處理客戶端發(fā)送的數(shù)據(jù),有需要的小伙伴可以了解下
    2024-10-10

最新評論

姚安县| 耿马| 伊宁县| 科尔| 绥化市| 琼海市| 朝阳区| 威远县| 金乡县| 平顶山市| 区。| 巩留县| 西贡区| 桓台县| 天津市| 永泰县| 吴忠市| 岚皋县| 柯坪县| 乐安县| 日照市| 株洲市| 宝山区| 洮南市| 扎鲁特旗| 阜康市| 四平市| 东光县| 锡林浩特市| 丰原市| 咸丰县| 田阳县| 宝鸡市| 平阳县| 乌拉特前旗| 宕昌县| 天柱县| 平顺县| 曲阜市| 湘乡市| 德惠市|