结构体,联合体union,枚举,sizeof

结构体中的位字段

有些信息在存储时并不需要占用一个完整的字节,有时只需要占用一个或者几个二进制位,为了节省存储空间并使得处理简便,C语言提供了一种数据结构,成为“位域”或者“位段”。

C与C++允许指定占用特定位数的结构成员,字段的类型应为整型或者枚举型 ,接下来是冒号:,然后后面跟一个数字,它指定了使用的位数,且可以使用没有名字的字段来提供间距。每个成员都被称为位字段(bit field)。例:

1 struct reg
2 {
3       unsigned int SN:4;
4       unsigned int :4;
5       bool  good: 4;
6 };

union

union与结构体的存放顺序是所有成员都从地地址开始存放。

union占用的内存大小要根据union的成员中占用内存最大的一项,还要考虑对齐问题。

大小端问题

大端存储格式:数据的高字节存放在低地址中,低字节存放在高地址中。

小端存储格式:数据的高字节存放在高地址中,低字节存放在低地址中。

printf函数在输出时候,要输出的变量用栈来保存,最后输出的先入栈,最先要输出的变量最后入栈,因此,按顺序入栈之后,再按照要求的格式按顺序输出。

printf函数是最右侧的元素先入栈。若入栈元素为char,short等小于4字节的类型,入栈时也是占4个字节,故printf("%d%d",‘a‘,‘b‘);时才不会发生输出错误(若入栈不是4个字节,出栈时是输出4个字节,就会发生错误);大于4个字节时,如long long ,按实际字节数入栈。字符串参数入栈的是只想字符串的指针。

一个关键点是:char,short等类型入栈时,高位补0还是补1。

当数是无符号类型时(如unsigned short)高位总是补1,当数是有符号类型时,如short,高位补符号位。

大小端也会影响到位字段的存放。定义的数据结构中如果包含bit位域,将以以下规则存放:

1)低字节都存放在低地址;

2)大端模式首先为字段的高bit位分配空间,小端模式首先为字段的低bit位分配空间;

3)大端模式首先存放地址的高bit位,小端模式首先存放地址的低bit位。

枚举

C++的enum 工具提供了另一种创建符号常量的方式,这种方式可以代替const。使用enum的句法与使用结构体的相似。

枚举是一种用户自定义的类型,定义的基本格式为:

enum 枚举类型名 {枚举常量1[=整型常数],枚举常量2[=整型常数],枚举常量3[=整型常数].......} [变量名列表]

花括号中的内容成为枚举表,其中的每一项成为枚举常量,[]中的整型数值是给枚举常量赋初值,可以省略,如果不赋初值,编译器会自动为每一个枚举常量赋一个不同的整型值,当枚举表中某个常量赋值后,则其后的成员按依次加1 的规则赋初值。

sizeof

sizeof是一个单目运算符,不是函数,sizeof操作符以字节形式给出了其操作数在内存中的存储大小。操作数可以是一个表达式或者括在括号里内的类型名,且会忽略在括号内的各种运算。如sizeof(a++) 中的++ 不会执行。

sizeof("\0") = 2.

汉字在内存中所占的字节数跟系统有关,windows下一般是占2个字节,但是在linux环境下,若系统使用UTF-8编码,则一个汉字占3个字节。

当数组做形参时,数组名当做指针使用,此时,sizeof(数组名)=sizeof(指针);32位系统下为4 。

struct 的空间计算

struct 空间计算比较复杂,一般遵循两个原则:

1)整体空间是占用空间最大的成员(的类型)所占的字节数的整数倍,但是在32位linux+gcc环境下,若最大成员类型 所占的字节数超过了4,如double是8,则整体空间是4的整数倍即可。

2)数据对齐原则-----内存按结构体成员的先后顺序排列,当排列到该成员变量时,其前面已经摆放的空间大小必须是该成员类型大小的整数倍,如果不够则补齐,一次向后类推。但在linux+gcc环境下,若某个类型所占的字节数超过了4,如double为8,则前面已经摆放的空间大小是4的整数倍即可,不够则补齐。

当结构体中嵌套有其他结构体时,则上面两个原则要修改为以下两条:

1)整体空间是子结构体与父结构体中占用空间最大的成员(的类型)所占字节数的整数倍,但在linux+gcc环境下,若最大成员类型所占的字节数超过了4,如double是8,则整体空间是4的整数倍即可。

2) 数据对齐原则------父结构体内按照结构体成员的先后顺序排列,当排列到子结构体时,其前面已经排好的空间大小必须是子结构体成员中最大类型大小的整数倍,如果不够,则补齐,依次类推。但是在linux+gcc环境下,若某成员类型占据的字节数大于4,如double是8,则前面已经摆放的空间大小是4的整数倍即可,不够则补齐。

含数组的结构体的空间计算

结构体中,数组是按照单个变量一个一个进行摆放 的,而不是视为一个整体。

含位域结构体的空间计算

位域成员不能单独被sizeof取值,但是可以用sizeof获取含有位域的结构体大小。

使用位域的主要目的是压缩存储,大致规则为:

1)如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段紧邻前一个字段存储,直到不能容纳为止。

  vs2010环境下,一个inta:4,如果后面不是位域,则占用4个字节,而在Dev-c++以及linux+gcc环境下,不论位于为何种类型,所占字节数以其时间占用的字节数为准,以方便后续结构体成员的摆放,即int:4,如果后面不是位域,仅占1个字节。

2)如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则其后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍。

3)如果相邻位域的字段类型不同,则各编译器的具体实现有差异,VC6采取不压缩,Dev-c++与linux+gcc采取压缩方式。

4)如果位域字段之间穿插着非位域字段,则不进行压缩。

5)整个结构体的总大小为最宽基本类型成员大小的整数倍。

使用"#pragma pack "时结构体空间的计算

#pragma pack(n)   编译器将按照n个字节对齐

#pragma pack()     取消自定义字节对齐方式。

注意,如果结构体成员中最大的成员类型大小都小于n,则n失效,即按照结构体中最大类型成员的大小进行对齐,反之,则以n对齐。

offsetof(item) = min( n , sizeof( item )  )

#pragma pack(push)     将当前pack设置压栈保存

#pragma pack(pop)     恢复先前的pack设置

空结构体的大小为    1
enum枚举的空间计算

enum只是定义了一个常量集合,里面没有“元素",而枚举类型是当做int类型存储的,故枚举类型的sizeof值都为4.

enum day {morning , moon , aftermoon} today;

sizeof (day) = 4 ,sizeof (today ) = 4;

string name;

name.size() 计算的是长度,不包含里面的‘\n‘;

函数以及类型重定义不占字节。
时间: 2024-11-05 21:23:22

结构体,联合体union,枚举,sizeof的相关文章

C语言 结构体(联合体)对齐规则

/* 结构体(联合体)对齐规则 */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* * 原则1.第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储). * 原则2.结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最宽基本类型大小的整数倍地址开始存储. *原则3.结构

C数组&amp;结构体&amp;联合体快速初始化

背景 C89标准规定初始化语句的元素以固定顺序出现,该顺序即待初始化数组或结构体元素的定义顺序. C99标准新增指定初始化(Designated Initializer),即可按照任意顺序对数组某些元素或结构体某些成员进行选择性初始化,只需指明它们所对应的数组下标或结构体成员名.GNU C将其作为C89模式的扩展. 借助指定初始化特性,可实现数组或结构体元素的快速初始化. 1 数组初始化 在数组初始化列表中使用"[index常量表达式]=value"形式可对index所指定的某个元素进

结构体/联合体 所占用内存

1 #include "stdafx.h" 2 #include <iostream> 3 using namespace std; 4 5 typedef struct Parameter{ 6 int a; 7 long b; 8 double c; 9 int d; 10 }Parameter; 11 12 typedef union Para{ 13 unsigned a; 14 double b; 15 long c; 16 int d; 17 }Para; 18

C语言-结构体-联合体

结构体 在Java中,我们要表示一个复合的数据类型就会使用对象去封装.而C就有结构体. 结构体是C语言中自定义的数据类型,是一组变量的集合,有别于数组,数组仅限于同一种数据类型,而结构体可以是任何数据类型,包括数组.结构体里面的每一个变量或者数组都是结构体的成员. 下面来看看结构体的基本使用 14-18行,定义了一个名称为Person的结构体,结构体里面有 age,money,sex 三种数据类型: 20-24行,是结构体的声明一个名为 P 的 Person 变量,并赋值: 25-27行,是结构

(三)结构体指针、sizeof

(一)结构体指针定义 今天上班写了一段测试代码,结果在linux下编译出现段错误,刚开始一直找不到原因,后来找了度娘才搞懂了.我先贴出来第一次写的代码以及gcc编译器下报的错误: #include<stdio.h> typedef struct { int a; char str; int b[5]; }St; int main() { St * Ds; Ds -> a = 5; Ds -> str = 'a'; Ds -> b[5] = 2; printf("a

被遗忘的C结构体打包技术

今天看到的一篇文章,记录一下:https://github.com/ludx/The-Lost-Art-of-C-Structure-Packing 失传的C结构体打包技艺 作者:Eric S. Raymond 原文链接:http://www.catb.org/esr/structure-packing/ 谁应阅读本文 本文探讨如何通过手工重新打包C结构体声明,来减小内存空间占用.你需要掌握基本的C语言知识,以理解本文所讲述的内容. 如果你在内存容量受限的嵌入式系统中写程序,或者编写操作系统内核

C-函数指针,指针函数,构造体之结构体

指针函数: 返回值是指针的函数 指针函数的定义: 一般形式: 类型说明符 *函数名(形参表){ 函数体 } 其中, 函数名之前加了’*’ 号表明这是一’指针型函数, 即返回值是一个指针. 类型说明符表示了返回的指针所指向的数据类型 函数指针: 一个函数在内存中总是占用一段连续的内存区, 而函数名就是该函数所占内存区的首地址——把函数的这个首地址(入口地址) 赋予一个指针变量, 使该指针变量指向该函数. 然后通过指针变量就可以找到并调用这个函数——这种指向函数的指针变量称为”函数指针变量” 类型说

C语言结构体训练

结构体大小和内存结构 1 #define _CRT_SECURE_NO_WARNINGS 2 #include<stdio.h> 3 #include<string.h> 4 #include<stdlib.h> 5 6 //结构体需要根据数据类型进行内存对齐 7 //struct stus 8 //{ 9 // char name[20];//20 10 // unsigned int age;//4 11 // char tel[15];//15 12 // cha

结构体及共用体的初始化方法

结构体初始化: /************************************************************ *  全局变量定义 ************************************************************/ AD_CTL_ST g_AdCtl; //定义结构体变量 AD_BUF_ST g_AdBuf[BUF_NUM]; //定义结构体数组 /****************************************

位域结构体简介

最近实习接触到一个新的知识点,C/C++的位域结构体. 以下开始摘抄自:here 位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间.含有位段的结构体(联合体)称为位段结构.采用位段结构既能够节省空间,又方便于操作. 位段的定义格式为: 1 type [var]: digits 其中type只能为int,unsigned int,signed int三种类型(int型能不能表示负数视编译器而定,比如VC中int就默认是signed int,能够表示负数).位段名