sizeof()操作符,求佔用空間,對數組而言大小爲 type大小 * 數據個數;
int a[] = {1,2,3,4,5}
sizeof(a) = 20
sizeof(&a) = 4
特殊的:在string時,由於字符串本質上就是自帶‘\0’結尾的 char[] 數組,而char 的大小有恰好爲1,
因此sizeof()就正好會是數組的長度;
在C++98中是不允許對類的非靜態成員變量使用sizeof()的,而在C++11中是合法的;
根據 C99 規定,sizeof是一個編譯時刻就起效果的運算符,運行時在其內的任何運算都沒有意義;
int i = 10;
sizeof(i++); // 4 此時i=10, 並不會自加,裏面的運算是無意義的;
int size = sizeof(Volume) / sizeof(Volume[0]); // Volume[0]並不起作用,只看其類型
strlen() 在對字符串計算時 以遇到'\0'結束符爲準,不包含末尾的'\0' 字符(或內存中的內容爲0)的長度的;
.length() (容器)字符串的長度,不包含結尾的'\0';
.size() (容器)字符串的長度'\0';
strcpy() 拷貝函數其實是從指定位置覆蓋,再加上‘\0’,而用%s輸出就到'\0'爲止。。。會在 最後自動 添加 '\0' 作爲結束符,,
--------------------------------------------------------------------------------------
例題1:
char dog[]="wang\0miao";
cout << sizeof(dog) << endl;// 10
cout << strlen(dog) << endl;// 4
例題2
char str[] = "ab\012\\n";
printf("%d \n", sizeof(str) );//6
printf("%d \n", strlen(str) );//5
解釋例題2 :
\012 \0表示8進制(後面跟 <8 的數據的話) 此處表8進制的的10,也即ASIIC符號 \n ,同時\0也可表示字符串結束;
\\ 表示 斜杆;
最終字符爲 a b \n \n \0
注:\ 表示轉義字符標誌;
例3
char c1[] ={'a', 'b', '\0', 'd', 'e'};
char c2[] ="hello";
sizeof(c1) strlen(c1); // 5 2
sizeof(c2) strlen(c2); // 6 5
例4
char *str1 ="hello";
char str2[] = "hello";
sizeof(str1) stelen(str1) // 4, 5(32位OS上,在64位OS上爲:8, 5)
區別:str1是變量,str2是char const 類型;
#pragma pack(n) // 指定內存對齊方式,往後的的代碼什麼的不按自身寬度對齊而是按指定寬度對齊;
#pragma pack() // 取消用戶自定義字節對齊方式
#pragma pack的n值等於或超過所有數據成員長度的時候,這個n值的大小將不產生任何效果。
__attribute((aligned (n))),讓所作用的結構成員對齊在n字節自然邊界上。
如果結構中有成員的長度大於n,則按照最大成員的長度來對齊。
__attribute__ ((packed)),取消結構在編譯過程中的優化對齊,按照實際佔用字節數進行對齊。
GCC默認按4字節對齊,
對於標準數據類型,地址只要是它的長度的整數倍就行了,而非標準數據類型按下面的原則對齊:
數組:按照基本數據類型對齊,第一個對齊了後面的自然也就對齊了。
枚舉:只佔4個字節;
聯合體:大於等於其成員中最寬的成員,且是其他成員變量基本類型的整數倍;
結構體:結構體中數據成員都要對齊,且結構體整體也需要對齊(整體對齊爲數據成員最大基本類型的整數倍);
類:看下文;
定義格式:
enum 枚舉名 {枚舉元素1, 枚舉元素2, ……};
注意:第一個枚舉成員的默認值爲整型的 0,後續枚舉成員的值在前一個成員上加 1。
enum season {spring, summer=3, autumn, winter};
沒有指定值的枚舉元素,其值爲前一元素加 1。也就說 spring 的值爲 0,summer 的值爲 3,
autumn 的值爲 4,winter 的值爲 5
// GCC 默認 4字節對齊
union test{
char s[9]; // 9
int a; // 4
double b; // 8
};
sizeof( test ); //>=最寬數據成員9, 且同時是其他類型char(1)、(int)4和double(8)的整數倍, 因此爲16
union test{
char s[8]; // 8
int a; // 4
double b; // 8
};
printf("%d\n", sizeof( test ) ); // >=最寬數據成員8, 且同時是其他類型char(1)、
(int)4和double(8)的整數倍, 因此爲8
struct struct_test_1{
char a; // 1
int b; // 4
double c; // 8
}test1;
sizeof( test1 ); // 16
struct struct_test_2{
char a; // 1
double b; // 8
int c; // 4
static int d; // 存放在靜態數據區,sizeof() 不計static所佔用空間
}test2;
sizeof( test2 ) // 24
對struct_test_2分析:
首先char a 申請一個字節空間,開闢首地址,之後double b存入; 它會認爲內存是以自己的大小(double = 8 byte)來劃分,
因此元素放置在自身寬度的整數倍開始(原則一),故b不從偏移1開始,因爲不是整數倍,故中間填充7字節,此時消耗16字節,
再開闢int c,4 字節,是從4字節的整數倍開始,故消耗了20字節。此時存儲單元不是最寬元素(8bytes)的整數倍,
故按最寬元素整數倍對齊(原則二);一共消耗24 字節。
struct Data
{
int a; // 4
float b; // 4
double c; // 8
char d[21]; // 21
}data;
printf("%d\n", sizeof(data) ); // 40 整體對齊爲 數據成員最大基本類型(double)的整數倍
有些數據在存儲時並不需要佔用一個完整的字節,只需要佔用一個或幾個二進制位即可。
例如開關只有通電和斷電兩種狀態,用 0 和 1 表示足以,也就是用一個二進位。
正是基於這種考慮,C語言又提供了一種叫做 位域 的數據結構。位域本質上是一種結構類型,
不過其成員是按二進制位分配的。並且其類型必須是int型,這就包括有符號和無符號的。
在結構體或是聯合體定義時,我們可以指定某個成員變量所佔的用的二進制(bit)位數,這就是位域。
位域的使用和結構體成員的使用相同,其一般形式爲:
變量類型 位域變量名:位域 其中(位域變量名爲可選項,)
struct bs{
int a:8;
int b:2;
int c:5;
};
printf("%d ", sizeof(struct bs) ); // 4
位域使用規則如下:
1、位域的寬度不能超過它所依附的數據類型的長度, 比如:unsigned int,長度爲 4 個字節,數字就不能超過 32
2、位域可以無位域名,這時它只用來作填充或調整成員位置。因爲沒有名稱,無名的位域是不能使用的。
位域存儲規則如下:
1、依然遵循struct的 對齊規則;
2、當相鄰成員的類型相同時,如果它們的位寬之和小於類型的 sizeof 大小,那麼後面的成員緊鄰前一個成員存儲,
直到不能容納爲止;如果它們的位寬之和大於類型的 sizeof 大小,那麼後面的成員將從新的存儲單元開始,其偏移量爲類型大小的整數倍。
struct bs{
int a:26;
int b:2;
int c:5;
};
printf("%d ", sizeof(struct bs) ); // 8
3、如果成員之間穿插着非位域成員,那麼不會進行壓縮。
struct bs{
int a:26;
int b;
int c:5;
};
printf("%d ", sizeof(struct bs) ); // 12
4、當相鄰成員的類型不同時,不同的編譯器有不同的實現方案,GCC 會壓縮存儲,而 VC/VS 不會。
struct A{
int a;//4
short b;//2+2
int c;//4
char d;//1+3
};
struct B{
int a; // 4
short b; // 2
char d;// 1 + 1
int c; // 4
};
sizeof(A) = 16, sizeof(B) = 12
實例2
struct foo{
char a; // 1 + 3
int b[10]; // 4 * 10
char c;// +1
};// 48
void main_2()
{
struct foo f={'X', {10,20,30,40,50,60,70,80,90}, 'F'};
cout << "單個成員變量值" << endl;
printf("%c %d %c \n", f.a, f.b[0], f.c);
// cout << f.a<< " " << f.b[0]<< " " << f.c<< endl; // f.b[0] 輸出是有錯誤的
cout << "相對偏移量" << endl;
printf ("sizeof() = %d\n", sizeof(foo) );
printf ("offsetof(struct foo,a) is %d\n",(int)offsetof(struct foo,a));//輸出 0
printf ("offsetof(struct foo,b) is %d\n",(int)offsetof(struct foo,b));//輸出 1
printf ("offsetof(struct foo,c) is %d\n",(int)offsetof(struct foo,c));//輸出 11
cout << "相對地址" << endl;
printf("struct address:0x%x\n",&f);
printf("struct member a address:0x%x\n",&(f.a) );
printf("struct member b address:0x%x\n",&(f.b) );
printf("struct member c address:0x%x\n",&(f.c) );
cout << "\n用地址操作單個成員變量值" << endl;
char *p = (char *)(&f);
// 由於存在 字節對齊問題
printf("地址:%#x 內容:%c \n", p, *p);
printf("地址:%#x 內容:%d \n", p+4, *(p+4) );
printf("地址:%#x 內容:%d \n", p+8, *(p+8) );
printf("地址:%#x 內容:%c \n", p+44, *(p+44) );
}
class A{
};
cout << "sizeof(A) "<< sizeof(A) << endl;// 1
class A{
int a;
double c;
char b;
union{
int aa;
char bb[9];
double cc;
}test;
};
cout << "sizeof(A) "<< sizeof(A) << endl;// 40 = 4 + 4 + 8 + 1 + 7 + 16
class B{
public:
void func1(){}
void func2(){}
};
cout << "sizeof(A) "<< sizeof(A) << endl;// 1
class B{
public:
void func1(){}
void func2(){}
virtual void func3() {}
virtual void func4() {}
};
cout << "sizeof(A) "<< sizeof(A) << endl;// 4
class B
{
private:
char ch;
virtual void func0() { }
};
class BB: public B
{
public:
int e;
virtual void func0() { }
virtual void func1() { }
};
class BB1: virtual public B // 虛繼承
{
public:
int e;
virtual void func0() { }
virtual void func1() { }
};
cout<< "sizeof(B)" << sizeof(B) <<endl; // 8
// B的內存分佈
// 4字節 虛表指針
// 1字節 ch
// 3字節 補齊,因爲最大的字段(虛表長度)size爲4,所以結構體補全成4的倍數
cout<< "sizeof(BB)"<< sizeof(BB) <<endl; // 12
cout<< "sizeof(BB1)"<< sizeof(BB1) <<endl; // 16