tft每日頭條

 > 科技

 > c語言中的long占位符

c語言中的long占位符

科技 更新时间:2024-05-16 14:24:53

構成電子計算機基本邏輯單元的晶體管可以表示兩種狀态,用二進制描述就是0或1,稱為一個二進制位(bit),多個晶體管的組合可以實現邏輯電路,數據和指令都可以以二進制的序列來表示。

通常以8個二進制位組成一個字節(byte),以字節為單位進行編址。

CPU在單位時間内能一次處理的二進制數的位數叫字長(word size)。字長指明指針數據的标稱大小(nominal size)。對于一個字長為n位的機器而言,虛拟地址的範圍為0-2^n-1,程序最多可以訪問2^n個字節。如32位機器的虛拟地址範圍為0x~0xFFFFFFFF。32位CPU表示該CPU處理的字長為32位,即一次處理4個字節。32位操作系統表示支持32位的CPU。64位CPU —指的是該CPU處理的字長為64位,即一次處理8個字節。64位操作系統表示支持64位的CPU,操作系統通常向後兼容,所以也支持32位操作系統。

使用PAE36技術的32位CPU是36根地址線,使用PAE40技術的Intel x86-64 CPU是40根地址線,使用PAE52技術的AMD x86-64 CPU是52根地址線。

C語言支持位級(bitwise)操作,其數據類型類型有一個字節長度的char類型,一個字長的int類型,指針本身的存儲也使用一個字長。

1 位級(bitwise)處理

C語言支持按位與、或、非操作,也支持移位操作。位操作的一個顯著用途就是節省存儲空間。

如在公曆轉農曆的程序中,可以使用一個unsigned int來存儲一個年份中的諸多信息:

如2019年的信息用0x0A9345表示,其二進制位為0000 1010 1001 00110 10 00101。

(16進制解析,每一個16進制位(0-f)是4個二進制位:0000-1111)

20-23位,其十進制值表示閏月月份,值為0 表示無閏月(第23位代表最高位,最左邊)

7到19位,分别代表農曆每月(在閏年有13個月)的大小,每一位代表一個月份。

(1表示大月為30天,0表示小月29天)

5到6位,其十進制值表示春節所在公曆月份(此處是2月)

0到4位,其十進制值表示春節所在公曆日期(此處是5日)

解析出不同的位組便可以得到該年不同的信息。

不同的年份可以存儲到一個數組中:

unsigned int LunarCalendarTable[199] = { 0x069349,0x7729BD,0x06AA51,0x0AD546,0x54DABA,0x04B64E,0x0A5743,0x452738,0x0D264A,0x8E933E,/*2081-2090*/ 0x0D5252,0x0DAA47,0x66B53B,0x056D4F,0x04AE45,0x4A4EB9,0x0A4D4C,0x0D1541,0x2D92B5 /*2091-2099*/ };

點陣數字和字符信息也可以用字符數組存儲和處理:

/* 輸出點陣數字:8個char即可保存64個位的數據,例如3: a[3]({0x00,0x1e,0x30,0x30,0x1c,0x30,0x30,0x1e}, //3 包括有8個十六進制的數,每行一個十六進制數,并且換成二進制的表示,會是什麼樣的呢? 00000000 //0x00 00011110 //0x1e 00110000 //0x30 00110000 //0x30 00011100 //0x1c 00110000 //0x30 00110000 //0x30 00011110 //0x1e 請看1出現的地方,可以借着鼠标按1出現的軌迹跟着劃一劃,不就是 數字3字型的輪廓嗎? 隻不過,耳朵狀的3是反着的(這自有道理,看完程序1自會明白)。 ———————————————— */ #include <iostream> using namespace std; char a[10][8]= { {0x00,0x18,0x24,0x24,0x24,0x24,0x24,0x18}, //0 {0x00,0x18,0x1c,0x18,0x18,0x18,0x18,0x18}, //1 {0x00,0x1e,0x30,0x30,0x1c,0x06,0x06,0x3e}, //2 {0x00,0x1e,0x30,0x30,0x1c,0x30,0x30,0x1e}, //3 {0x00,0x30,0x38,0x34,0x32,0x3e,0x30,0x30}, //4 {0x00,0x1e,0x02,0x1e,0x30,0x30,0x30,0x1e}, //5 {0x00,0x1c,0x06,0x1e,0x36,0x36,0x36,0x1c}, //6 {0x00,0x3f,0x30,0x18,0x18,0x0c,0x0c,0x0c}, //7 {0x00,0x1c,0x36,0x36,0x1c,0x36,0x36,0x1c}, //8 {0x00,0x1c,0x36,0x36,0x36,0x3c,0x30,0x1c}, //9 }; int main() { int n=0,i,j,k,m,x; cout<<"請輸入需要顯示的數字:"; int c[8]; cin>>n; for(k=0; n&&k<8; k ) //c數組将分離出n中的各位數,不過是倒着的,例n=123,c中保存3 2 1 { c[k]=n; n/=10; } //循環結束,将由k記住n是幾位數,此處限最多8位數 for(i=0; i<8; i ) //一共要顯示8行,不是依次顯示k個數字,而是依次顯示k個數字中對應的每一行 { for(m=k-1; m>=0; m--) //要顯示n=123, c中是倒着保存各位數的,所以m由大到小 { x=a[c[m]][i]; //現在要顯示的數字是c[m],所以取a數組中的第c[m]行,第i列數據 for(j=0; j<8; j ) { if(x%2) cout<<'*'; else cout<<' '; x=x/2; } } cout<<endl; } while(1); return 0; } /* 請輸入需要顯示的數字:68 *** *** ** ** ** **** ** ** ** ** *** ** ** ** ** ** ** ** ** *** *** */

浮點編碼可以通過位域來解析:

#include <stdio.h> void floatNumber_1(){ struct FF{ // 小端模式模拟double類型編碼 unsigned l:32; // 剩下的小數位 unsigned m:15; // 剩下的小數位 unsigned k:5; // 取5位小數 unsigned j:11; // 階碼 unsigned i:1; // 符号位 }; union UN { double dd; FF ff; }; UN un; un.dd = -15.75; // -1111.11 printf("%d\n",un.ff.i); // 1 printf("%d\n",un.ff.j); // 1023 3 printf("%d\n",un.ff.k); // 31 也就是二進制的11111 } void floatNumber_2(){ struct FF{ // 小端模式模拟double類型編碼 unsigned l:32; // 剩下的小數位 unsigned m:15; // 剩下的小數位 unsigned k:5; // 取5位小數 unsigned j:11; // 階碼 unsigned i:1; // 符号位 }; union UN { double dd; FF ff; }; UN un; un.ff.i = 1; un.ff.j = 1023 3; un.ff.k = 31; // 二進制的11111 un.ff.m = 0; un.ff.l = 0; printf("%.2lf\n",un.dd); //un.dd = -15.75;// -1111.11 } int main() { floatNumber_1(); floatNumber_2(); while(1); return 0; } /* 1 1026 31 -15.75 */

位域、共用體和可以解析漢字的GBK或GB2312編碼:

void cngb() { union{ struct { unsigned int i:4; unsigned int j:4; unsigned int k:4; unsigned int L:4; unsigned int m:4; unsigned int n:4; }; char hanzi[3]; }hz; fflush(stdin); puts("查詢gb2312碼,請輸入一個漢字:"); gets(hz.hanzi); //strcpy(hz.hanzi,"中"); printf("%X%X%X%X\n",hz.j,hz.i,hz.L,hz.k); }

2 字節級(byte)處理

典型類型:char,char的長度是一個字節。

<limits.h>定義了一個宏:CHAR_BIT。

typedef unsigned char byte;

顯示double的字節編碼:

void showBytes(unsigned char* start, int len) { for(int i=0;i<len;i ) printf(" %.2x",start[i]); printf("\n"); } void showDoubleByte(double x) { showBytes((unsigned char*)&x,sizeof(double)); } void showBytesByBig(unsigned char* start, int len) { unsigned int i = 0x00000001; unsigned char* c = (unsigned char*)&i; if(*c==1)// 小端返回true,大端返回0 { for(int i=len-1;i>=0;i--) printf(" %.2x",start[i]); printf("\n"); } }

memmove()函數實現:

memmove()由src所指定的内存區域賦值count個字符到dst所指定的内存區域。 src和dst所指内存區域可以重疊,但複制後src的内容會被更改。函數返回指向dst的指針。

void * my_memmove(void * dst,const void * src,int count) { void * ret = dst; if(dst <= src || (char *)dst >= ((char *)src count)) { while(count--) { *(char *)dst = *(char *)src; dst = (char *)dst 1; src = (char *)src 1; } } else { dst = (char *)dst count - 1; src = (char *)src count - 1; while(count--) { *(char *)dst = *(char *)src; dst = (char *)dst - 1; src = (char *)src - 1; } } return(ret); } int main() { char a[12]; puts((char *)my_memmove(a,"ammana_babi",16)); system("pause"); return 0; }

二進制文件浏覽:

#include<iostream> #include<iomanip> #include <fstream> #include<cstdlib> using namespace std; int main( ) { char c[16]; char f[100]; cout<<"請輸入文件名:"; cin>>f; ifstream infile(f,ios::in|ios::binary); if(!infile) { cerr<<"open error!"; exit(1); } while(!infile.eof()) { infile.read(c,16); if(!infile.eof()) { for(int i=0; i<16; i) cout<<setfill('0')<<setw(2)<<hex<<int((unsigned char)(c[i]))<<" "; cout<<'\t'; for(int i=0; i<16; i) cout<<(c[i]?c[i]:'.'); cout<<endl; } } return 0; }

位級與字節級結合處理的實例:

考慮用一個short類型存儲一個有效日期(年份取末兩位):

/* 考慮用一個short類型存儲一個有效日期(年份取末兩位): Year(0-99) 7 bits Month(1-12)4 bits Day(l-31) 5 bits 如2021/11/22 1234567890123456 0000000000000000 0000000000010101 // year左移9位留下7位有效位 0000000000001011 // Month左移5位留給Day 0000000000010110 */ // 向整數中壓縮數據 #include <iostream> #include <iomanip> using namespace std; unsigned short dateShort(short year,short mon,short day) { unsigned short date; date = (year << 16-7) | (mon << 5) | day; return date; } void datePrint(unsigned short date) { struct Date{ unsigned day:5; unsigned mon:4; unsigned year:7; }; Date *d = (Date*)&date; printf("20%d/%d/%d",d->year,d->mon,d->day); } int main() { unsigned short date = dateShort(21,11,22); datePrint(date); // 2021/12/22 getchar(); return 0; }

按16進制顯示數據:

#include <stdio.h> void hexPrint(int n) { if(n==0) printf("00 "); char str[5] = {0}; int len = 0; while(n) { int m = n; n /= 16; if(m<10) str[len ] = m '0'; else str[len ] = m 'A'-10; } --len; if(len%2==0) printf("0"); while(len>=0) { printf("%c",str[len--]); if(len%2) printf(" "); } } hexPrint2(int n) { char str[5] = {0}; sprintf(str,"%X",n); printf("%s ",str); } void bitsPrint(void *type,unsigned size) { unsigned char*p = (unsigned char*)type; int endian = 1; if(*(char*)&endian) printf("小端字節序:"); for(unsigned i=0;i<size;i ) //printf("%d ",*p ); hexPrint(*p ); //hexPrint2(*p ); printf("\n"); } int main() { int a = -123456789; bitsPrint((void*)&a,sizeof a); // 小端字節序:EB 32 A4 F8 double b = -15.75; // bitsPrint((void*)&b,sizeof b); // 小端字節序:00 00 00 00 00 80 2F C0 getchar(); return 0; }

3 字級(word)處理

典型類型:int,int的長度是一個字長,32位CPU或操作系統是4個字節,64位是8個字節。

typedef unsigned int word;

3.1 寄存器的長度是一個字長

當讀寫double數據類型時,需要兩條mov指令:

10: double dd = 15.751; 00401044 mov dword ptr [ebp-18h],126E978Dh 0040104B mov dword ptr [ebp-14h],402F8083h

當讀寫一個字長或以下的數據時,隻需要一個寄存器,一條mov指令。

同樣的,當返回值是一個字長或以下的數據時,可用寄存器返回。如果是double,則用浮點棧返回,如果是複合類型,則需要壓入一個存儲返回值的起始地址,将返回值返回到這個起始地址标識的被調函數的棧幀空間。

3.2 指針的标度是一個字長

printf("%d\n",sizeof(void*)); // 4,32位系統

3.3 棧按一個字長對齊

其根源還是在于寄存器的長度是一個字長,一次訪問一個字長的内存空間,如果不對齊,有可能就需要更多次的訪問,适當的浪費一點内存空間來換取效率(以空間換時間)是可取的。

#include <stdio.h> void bufferOverflow() { char ch = 'a'; // 棧對齊為4個字節 int base = 0; char buf[5] = {0}; // 棧對齊為8個字節 puts("輸入你構造的字符串,模拟緩沖區溢出:"); gets(buf); if(base==0x64636261){ puts("緩沖區溢出改寫了鄰近區内存!"); } } int main() { bufferOverflow(); // 輸出12345678abcd會執行puts(),678用于棧對齊, // abcd給到了base,'\0'給到了ch return 0; } /*output: 輸入你構造的字符串,模拟緩沖區溢出: 12345678abcd 緩沖區溢出改寫了鄰近區内存! */

看函數的棧幀:

c語言中的long占位符(C按位字節級)1

棧幀圖示:

c語言中的long占位符(C按位字節級)2

如果輸入超過15個字符(其中有'\0'),則會破壞ebp,引發運行錯誤。

結構體也需要同樣的對齊(包括成員的對齊及整體的對齊):

#include <stdio.h> struct Align{ char ch; int base; char buf[5]; }; int main() { Align align = {'a',1,"abcd"}; getchar(); return 0; }

函數内存映像:

c語言中的long占位符(C按位字節級)3

-End-

,

更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!

查看全部

相关科技资讯推荐

热门科技资讯推荐

网友关注

Copyright 2023-2024 - www.tftnews.com All Rights Reserved