https://www.cnblogs.com/jingzhishen/p/3696293.html
sizeof()用法匯總
sizeof()功能:計算數據空間的字節數
1.與strlen()比較
strlen()計算字符數組的字符數,以"\0"為結束判斷,不計算為'\0'的數組元素。
而sizeof計算數據(包括數組、變量、類型、結構體等)所占內存空間,用字節數表示。
2.指針與靜態數組的sizeof操作
指針均可看為變量類型的一種。所有指針變量的sizeof 操作結果均為4。
注意:int *p; sizeof(p)=4;
但sizeof(*p)相當於sizeof(int);
對於靜態數組,sizeof可直接計算數組大小;
例:int a[10];char b[]="hello";
sizeof(a)等於4*10=40;
sizeof(b)等於6;
注意:數組做型參時,數組名稱當作指針使用!!
void fun(char p[])
{sizeof(p)等於4}
char str[20]="0123456789";
int a=strlen(str); //a=10;
int b=sizeof(str); //而b=20;
char ss[] = "0123456789";
sizeof(ss) 結果 11 ===》ss是數組,計算到\0位置,因此是10+1
sizeof(*ss) 結果 1 ===》*ss是第一個字符
char ss[100] = "0123456789";
sizeof(ss) 結果是100 ===》ss表示在內存中的大小 100×1
strlen(ss) 結果是10 ===》strlen是個函數內部實現是用一個循環計算到\0為止之前
int ss[100] = "0123456789";
sizeof(ss) 結果 400 ===》ss表示在內存中的大小 100×4
strlen(ss) 錯誤 ===》strlen的參數只能是char* 且必須是以'\0'結尾的
char q[]="abc";
char p[]="a\n";
sizeof(q),sizeof(p),strlen(q),strlen(p); 結果是 4 3 3 2
一些朋友剛開始時把sizeof當作了求數組元素的個數,如今你應該知道這是不對的,那么應該怎么求數組元素的個數呢Easy,通常有下面兩種寫法:
1.int c1 = sizeof( a1 ) / sizeof( char ); // 總長度/單個元素的長度
2.int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 總長度/第一個元素的長度
Student stus[4]={
{"humingtao",24,99},
{"zhaoweisong",23,66},
{"chenfengchang",21,88},
{"zhuwenpeng",20,77}
數組長度 count = sizeof(stus)/sizeof(stus[0]
double* (*a)[3][6];
cout<<sizeof(a)<<endl; // 4 a為指針
cout<<sizeof(*a)<<endl; // 72 *a為一個有3*6個指針元素的數組
cout<<sizeof(**a)<<endl; // 24 **a為數組一維的6個指針
cout<<sizeof(***a)<<endl; // 4 ***a為一維的第一個指針
cout<<sizeof(****a)<<endl; // 8 ****a為一個double變量
offsetof(s,m)解析
const AVClass *class;
char *expr_str;
AVExpr *expr;
double var_values[VAR_VARS_NB];
enum AVMediaType type;
} SetPTSContext;
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_FILTERING_PARAM
static const AVOption options[] = {
{ "expr", "Expression determining the frame timestamp", OFFSET(expr_str), AV_OPT_TYPE_STRING, { .str = "PTS" }, .flags = FLAGS },
{ NULL }
};
&((s *)0)->m 是要取得類s中成員變量m的地址
由於這個類(或結構)的基址為0,這時m的地址當然就是m在s中的偏移了
我們許多人可能都使用過一些非揮發性的存儲器,如常見的EEPROM。我們經常使用它們在存儲一些系統的配置參數和設備信息。在所有的EEPROM中,通過串口訪問的占了大多數。一般來說,對串口的訪問都是按字節進行的,這使得我們不可避免會設計出下面的
接口去訪問EEPROM的信息:
ee_rd(uint16_t offset, uint16_t nBytes, uint8_t * dest);
定義一個數據結構和一個指向這個數據結構的指針,並初始化這個指針為EEPROM的起始地址EEPROM_BASE.
| i | f | c | | | |...
----------------------------
| | | | | | |...
----------------------------
| | | | | | |...
----------------------------
...
----------------------------
{
int i;
float f;
char c;
} EEPROM;
a.容易使代碼維護人員人誤以為在ee_rd接口內部也存在EEPROM的數據結構。
b.當你編寫一些自己感覺良好編譯器不報錯的代碼,比如pEE->f = 3.2,你可能意想不到災難將要來臨。
c.這個接口沒有很好地體現EEPROM所隱含的硬件特性。
比如成員f在EEPROM數據結構中的偏移量,這里為什么
要強制轉化0,這是個有深度的問題,在后面也會詳細說明*/
#define offsetof(type, f) ((size_t) \
((char *)&((type *)0)->f - (char *)(type *)0))
{
int i;
float f;
char c;
} EEPROM;
#define SIZEOF(s,m) ((size_t) sizeof(((s *)0)->m))
Good question.其實我們可以通過下面的方法解決。
{
char pad[EEPROM_BASE];/*使數據結構的前EEPROM_BASE個字節填"空"*/
int i;
float f;
char c;
} EEPROM;
---------------------------- 0x00000000
| | | | | | |...
----------------------------
...
---------------------------- <-EPPROM_BASE:0x00000a10
| i | f | c | | | |...
----------------------------
| | | | | | |...
----------------------------
...
這種映射使原本復雜的寄存器訪問變得象訪問普通的RAM地址一樣方便。
在我們視頻會議系統中,PowerPC 8250訪問外部的ROM控制器(ROM controller)的
寄 存器就是通過這種方式實現的。ROM控制器所有的寄存器被映射到從I/O寄存器空間基地址0x10000000(IO_BASE)偏移 0x60000(ROMCONOffset)字節的一段內存。每個寄存器占用四個字節,並有一個數據結構與它們對應。比如控制ROM控制器工作狀態的寄存 器對應數據結構 ROMCON_ROM_CONTROL,配置PCI總線A的寄存器對應數據結構 ROMCON_CONFIG_A,下面先看看這些數據結構的定義:
union {
struct {
UINT32 pad4:21; /* unused */
UINT32 pad3:2; /* reserved */
UINT32 pad2:5; /* unused */
UINT32 EnablePCIA:1;
UINT32 pad1:1; /* reserved */
UINT32 EnableBoot:1;
UINT32 EnableCpu:1; /*bit to enable cpu*/
} nlstruct;
UINT32 ConfigA;
} nlstruct4;
} nlunion;
} ROMCON_CONFIG_A, *PROMCON_CONFIG_A;
union {
struct {
UINT32 TransferComplete:1;
UINT32 pad3:1; /* unused */
UINT32 BondPad3To2:2;
UINT32 Advance:3;
UINT32 VersaPortDisable:1;
UINT32 pad2:1; /* unused */
UINT32 FastClks:1;
UINT32 pad1:7; /* unused */
UINT32 CsToFinClks:2;
UINT32 OeToCsClks:2;
UINT32 DataToOeClks:2;
UINT32 OeToDataClks:3;
UINT32 CsToOeClks:2;
UINT32 AddrToCsClks:2;
UINT32 AleWidth:2;
} nlstruct;
UINT32 RomControl;
} nlstruct4;
} nlunion;
} ROMCON_ROM_CONTROL, *PROMCON_ROM_CONTROL;
{
ROMCON_CONFIG_A ConfigA;
ROMCON_CONFIG_B ConfigB;
ROMCON_ROM_CONTROL RomControl;
...
} ROMCON, *PROMCON;
| | | | | | |...
----------------------------
| | | | | | |...
...
---------------------------- <-ROMCONOffset(ROMCON):0x60000
| | | | | | |...
---------------------------- <-ROMCON_ROM_CONTROL
...
----------------------------
估計有人可能會這樣做:
事先定義成員RomControl(ROMCON中用ROMCON_ROM_CONTROL定義的實例)相對與ROMCON的偏移量,
void rom_read(dword_t* src, uint32_t* dest);
void rom_write(dword_t* src, uint32_t* dest);
if(!tRomCtrl.nlunion.nlstruct.VersaPortDisable)
{
tRomCtrl.nlunion.nlstruct.VersaPortDisable = 1;
}
這樣做確實可以達到訪問相應寄存器的目的。但是,如果和ROM相關的寄存器很多,那么定義、記憶和管理那么多偏移量不是很不方便嗎?到這里,如果你對前面關於offsetof還有印象的話,我想你可能會作下面的優化:
#define ROMCON_ADDR(m) (((size_t)IO_BASE+\
(size_t)ROMCONOffset+\
(size_t) offsetof(ROMCON,m))
dword_t* pReg=(dword_t*) ROMCON_ADDR(ConfigA);
if(!tRomCtrl.nlunion.nlstruct. VersaPortDisable)
{
tRomCtrl.nlunion.nlstruct.VersaPortDisable = 1;
}
2.offsetof的來龍去脈
通過前面的舉例,你可能對如何使用offsetof已經不陌生了吧。offsetof對那些搞
C++ 的人可能很熟悉,因為offsetof類似於sizeof,也是一種系統操作符,你不用考慮它是怎么定義的。這個操作符offsetof的定義可以在 ANSI C 編譯器所帶的stddef.h中找到。在嵌入式系統里,不同開發商,不同架構處理器和編譯器都有不同的offsetof定義形式:
#define offsetof(s,m) (size_t)&(((s *)0)->m)
#define offsetof(s,m) (size_t)(unsigned long)&(((s *)0)->m)
#define offsetof(s,memb) ((size_t)((char *)&((s *)0)->memb-(char *)0))
#define offsetof(TYPE, MEMBER) __builtin_offsetof (TYPE, MEMBER)
((s *)0):強制轉化成數據結構指針,並使其指向地址0;
((s *)0)->m:使該指針指向成員m
&(((s *)0)->m):獲取該成員m的地址
(size_t)&(((s *)0)->m):轉化這個地址為合適的類型
{
unsigned int a:3;
unsigned int b:13;
unsigned int c:16;
}foo;