精华内容
参与话题
问答
  • Qt图形视图框架详解

    千人学习 2016-12-07 16:50:42
    Qt图形视图框架详解视频教程,介绍Qt中的Graphics View Framework,涉及View、Scene、Item的关系,如何自定义QGraphicsItem、处理Item之间的关联、如何布局及定义自己的布局Item、如何变幻Item、如何应用动画、如何...
  • python求和函数sum()详解

    万次阅读 多人点赞 2019-04-06 21:32:44
    python求和函数sum()详解 今天在学习的过程中,误用sum()函数,我又去查了查python sum()函数才恍然大悟。 我本来想算几个Int值相加的和,本以为很简单的事情,结果却很悲伤,例: >>>sum = sum(1,2,3) #...

    python求和函数sum()详解

    今天在学习的过程中,误用sum()函数,我又去查了查python sum()函数才恍然大悟。

    我本来想算几个Int值相加的和,本以为很简单的事情,结果却很悲伤,例:

    >>>sum = sum(1,2,3)         #结果很明显出现问题报错
    TypeError: sum expected at most 2 arguments, got 3
    

    傻乎乎的我以为只能算前两个数的和等于3,就又试了一下

    >>>sum = sum(1,2)           #结果还是报错
    TypeError: 'int' object is not iterable
    

    其实,我们所了解sum()函数语法是这样的
    sum(iterable[, start])

    其中

    • iterable – 可迭代对象,如:列表(list)、元组(tuple)、集合(set)、字典(dictionary)。

    • start – 指定相加的参数,如果没有设置这个值,默认为0。

      也就是说sum()最后求得的值 = 可迭代对象里面的数加起来的总和(字典:key值相加) + start的值(如果没写start的值,则默认为0)
      

    所以,我所求的几个int值的和可以写成这样

    >>>sum = sum([1,2,3])             # in list
    6
    

    如果我们加上start的话,应该是这样的

    >>> sum = sum([1,2,3],5)          #in list +start
    11
    >>> sum = sum((1,2,3))            #in tuple
    6
    >>> sum = sum({1,2,3})            #in set
    6
    >>> sum = sum({1:5,2:6,3:7})      #in dictionary key
    6
    >>> sum = sum(range(1,4))         #in range()
    

    学习这些过后,我们就可以正确的运用sum()函数了。

    别指望着看一遍就能记住和整掌握什么 – 请看第二遍,第三遍。

    展开全文
  • Linux中top命令参数详解

    万次阅读 多人点赞 2019-07-31 19:28:22
    top命令用法 top命令经常用来监控linux的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。 top的使用方式 top [-d number] | top [-bnp] 参数解释: -d:number代表秒数,表示top...

    top命令用法

    top命令经常用来监控linux的系统状况,是常用的性能分析工具,能够实时显示系统中各个进程的资源占用情况。

    top的使用方式 top [-d number] | top [-bnp]

    参数解释:

    -d:number代表秒数,表示top命令显示的页面更新一次的间隔。默认是5秒。 -b:以批次的方式执行top。 -n:与-b配合使用,表示需要进行几次top命令的输出结果。 -p:指定特定的pid进程号进行观察。

    在top命令显示的页面还可以输入以下按键执行相应的功能(注意大小写区分的):

    ?:显示在top当中可以输入的命令 P:以CPU的使用资源排序显示 M:以内存的使用资源排序显示 N:以pid排序显示 T:由进程使用的时间累计排序显示 k:给某一个pid一个信号。可以用来杀死进程 r:给某个pid重新定制一个nice值(即优先级) q:退出top(用ctrl+c也可以退出top)。

    top各输出参数含义

    下面是使用top命令来进行性能检测的截图:

    图一(ubuntu):

    图二(centos):

    一、top前5行统计信息

    第1行:top - 05:43:27 up 4:52, 2 users, load average: 0.58, 0.41, 0.30 
    第1行是任务队列信息,其参数如下:

    内容 含义
    05:43:27 表示当前时间
    up 4:52 系统运行时间 格式为时:分
    2 users 当前登录用户数
    load average: 0.58, 0.41, 0.30 系统负载,即任务队列的平均长度。 三个数值分别为 1分钟、5分钟、15分钟前到现在的平均值。

    load average: 如果这个数除以逻辑CPU的数量,结果高于5的时候就表明系统在超负荷运转了。 

    第2行:Tasks: 159 total, 1 running, 158 sleeping, 0 stopped, 0 zombie 
    第3行:%Cpu(s): 37.0 us, 3.7 sy, 0.0 ni, 59.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st 
    第2、3行为进程和CPU的信息 
    当有多个CPU时,这些内容可能会超过两行,其参数如下:

    内容 含义
    159 total 进程总数
    1 running 正在运行的进程数
    158 sleeping 睡眠的进程数
    0 stopped 停止的进程数
    0 zombie 僵尸进程数
    37.0 us 用户空间占用CPU百分比
    3.7 sy 内核空间占用CPU百分比
    0.0 ni 用户进程空间内改变过优先级的进程占用CPU百分比
    59.3 id 空闲CPU百分比
    0.0 wa 等待输入输出的CPU时间百分比
    0.0 hi 硬中断(Hardware IRQ)占用CPU的百分比
    0.0 si 软中断(Software Interrupts)占用CPU的百分比
    0.0 st  


    第4行:KiB Mem: 1530752 total, 1481968 used, 48784 free, 70988 buffers 
    第5行:KiB Swap: 3905532 total, 267544 used, 3637988 free. 617312 cached Mem 
    第4、5行为内存信息 
    其参数如下:

    内容 含义
    KiB Mem: 1530752 total 物理内存总量
    1481968 used 使用的物理内存总量
    48784 free 空闲内存总量
    70988 buffers(buff/cache) 用作内核缓存的内存量
    KiB Swap: 3905532 total 交换区总量
    267544 used 使用的交换区总量
    3637988 free 空闲交换区总量
    617312 cached Mem 缓冲的交换区总量。
    3156100 avail Mem 代表可用于进程下一次分配的物理内存数量

    上述最后提到的缓冲的交换区总量,这里解释一下,所谓缓冲的交换区总量,即内存中的内容被换出到交换区,而后又被换入到内存,但使用过的交换区尚未被覆盖,该数值即为这些内容已存在于内存中的交换区的大小。相应的内存再次被换出时可不必再对交换区写入。 

    计算可用内存数有一个近似的公式: 
    第四行的free + 第四行的buffers + 第五行的cached

    二、进程信息

    列名 含义
    PID 进程id
    PPID 父进程id
    RUSER Real user name
    UID 进程所有者的用户id
    USER 进程所有者的用户名
    GROUP 进程所有者的组名
    TTY 启动进程的终端名。不是从终端启动的进程则显示为 ?
    PR 优先级
    NI nice值。负值表示高优先级,正值表示低优先级
    P 最后使用的CPU,仅在多CPU环境下有意义
    %CPU 上次更新到现在的CPU时间占用百分比
    TIME 进程使用的CPU时间总计,单位秒
    TIME+ 进程使用的CPU时间总计,单位1/100秒
    %MEM 进程使用的物理内存百分比
    VIRT 进程使用的虚拟内存总量,单位kb。VIRT=SWAP+RES
    SWAP 进程使用的虚拟内存中,被换出的大小,单位kb
    RES 进程使用的、未被换出的物理内存大小,单位kb。RES=CODE+DATA
    CODE 可执行代码占用的物理内存大小,单位kb
    DATA 可执行代码以外的部分(数据段+栈)占用的物理内存大小,单位kb
    SHR 共享内存大小,单位kb
    nFLT 页面错误次数
    nDRT 最后一次写入到现在,被修改过的页面数。
    S 进程状态。D=不可中断的睡眠状态 R=运行 S=睡眠 T=跟踪/停止 Z=僵尸进程
    COMMAND 命令名/命令行
    WCHAN 若该进程在睡眠,则显示睡眠中的系统函数名
    Flags 任务标志

    其他

    默认进入top时,各进程是按照CPU的占用量来排序的。

    1、在top基本视图中,按键盘数字“1”可以监控每个逻辑CPU的状况: 

     
    2、敲击键盘‘b’(打开关闭加亮效果)top视图变换如下: 

    PID为16283为当前top视图中唯一的运行态进程。也可以敲击键盘‘y’来打开或者关闭运行态进程的加亮效果。

    3、敲击键盘‘x’(打开/关闭排序列的加亮效果),top视图变换如下: 

    可以看到现在是按"%CPU"进行排序的,可以按”shift+>”或者”shift+<”左右改变排序序列。

    4、改变进程显示字段

    在top基本视图中,敲击”f”进入另一个视图,在这里可以编辑基本视图中的显示字段:

     

    用上下键选择选项,按下空格键可以决定是否在基本视图中显示这个选项。

    top命令是一个非常强大的功能,但是它监控的最小单位是进程,如果想监控更小单位时,就需要用到ps或者netstate命令来满足我们的要求。

    参考文献

    1、https://blog.csdn.net/quiet_girl/article/details/50668126

    2、http://www.zhimengzhe.com/linux/298422.html

    展开全文
  • CAN总线详解

    万次阅读 多人点赞 2019-07-23 18:00:12
    1、简介 CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络。 优点: 传输速度最高到1Mbps,通信距离最远到10km,无损位仲裁机制,多主结构。...

    1、简介

    CAN是控制器局域网络(Controller Area Network, CAN)的简称,是一种能够实现分布式实时控制的串行通信网络。

    优点:

    传输速度最高到1Mbps,通信距离最远到10km,无损位仲裁机制,多主结构。近些年来,CAN控制器价格越来越低。

    Ø 低成本:ECUs通过单个CAN接口进行通信,布线成本低。

    Ø 高集成:CAN总线系统允许在所有ECUs上进行集中错误诊断和配置。

    Ø 可靠性:该系统对子系统的故障和电磁干扰具有很强的鲁棒性,是汽车控制系统的理想选择。

    Ø 高效率:可以通过id对消息进行优先级排序,以便最高优先级的id不被中断。

    Ø 灵活性:每个ECU包含一个用于CAN总线收发芯片,随意添加CAN总线节点。

    2、CAN总线网络

    CAN总线网络主要挂在CAN_H和CAN_L,各个节点通过这两条线实现信号的串行差分传输,为了避免信号的反射和干扰,还需要在CAN_H和CAN_L之间接上120欧姆的终端电阻。为什么是120Ω,因为电缆的特性阻抗为120Ω,为了模拟无限远的传输线。

    3、CAN收发器

    CAN收发器的作用是负责逻辑电平和信号电平之间的转换。

    即从CAN控制芯片输出逻辑电平到CAN收发器,然后经过CAN收发器内部转换将逻辑电平转换为差分信号输出到CAN总线上,CAN总线上的节点都可以决定自己是否需要总线上的数据。具体的引脚定义如下:

    can总线原理

    4、CAN信号表示

    CAN总线采用不归零码位填充技术,也就是说CAN总线上的信号有两种不同的信号状态,分别是显性的(Dominant)逻辑0和隐形的(recessive)逻辑1,信号每一次传输完后不需要返回到逻辑0(显性)的电平。

    显性与隐性电平的解释:

    CAN的数据总线有两条,一条是黄色的CAN_High,一条是绿色的CAN_Low。当没有数据发送时,两条线的电平一样都为2.5V,称为静电平,也就是隐性电平。当有信号发送时,CAN_High的电平升高1V,即3.5V,CAN_Low的电平降低1V,即1.5V。

    按照定义的:

    • CAN_H-CAN_L < 0.5V 时候为隐性的,逻辑信号表现为"逻辑1"- 高电平。

    • CAN_H-CAN_L > 0.9V 时候为显性的,逻辑信号表现为"逻辑0"- 低电平。

    5、CAN信号传输

    发送过程: CAN控制器将CPU传来的信号转换为逻辑电平(即逻辑0-显性电平或者逻辑1-隐性电平)。CAN发射器接收逻辑电平之后,再将其转换为差分电平输出到CAN总线上。

    接收过程: CAN接收器将CAN_H 和 CAN_L 线上传来的差分电平转换为逻辑电平输出到CAN控制器,CAN控制器再把该逻辑电平转化为相应的信号发送到CPU上。

     

    5、CAN数据传输

    CAN总线传输的是CAN帧,CAN的通信帧分成五种,分别为数据帧、远程帧、错误帧、过载帧和帧间隔。

    数据帧根据仲裁段长度不同分为标准帧(2.0A)和扩展帧(2.0B)

    帧起始

    由一个显性位(低电平)组成,发送节点发送帧起始,其他节点同步于帧起始;

    帧结束

    由7个隐形位(高电平)组成。

    仲裁段

    只要总线空闲,总线上任何节点都可以发送报文,如果有两个或两个以上的节点开始传送报文,那么就会存在总线访问冲突的可能。但是CAN使用了标识符的逐位仲裁方法可以解决这个问题。

    CAN总线控制器在发送数据的同时监控总线电平,如果电平不同,则停止发送并做其他处理。如果该位位于仲裁段,则退出总线竞争;如果位于其他段,则产生错误事件。

    帧ID越小,优先级越高。由于数据帧的RTR位为显性电平,远程帧为隐性电平,所以帧格式和帧ID相同的情况下,数据帧优先于远程帧;由于标准帧的IDE位为显性电平,扩展帧的IDE位为隐形电平,对于前11位ID相同的标准帧和扩展帧,标准帧优先级比扩展帧高。

    img

    数据段

    一个数据帧传输的数据量为0~8个字节,这种短帧结构使得CAN-bus实时性很高,非常适合汽车和工控应用场合如图27所示。

    数据量小,发送和接收时间短,实时性高,被干扰的概率小,抗干扰能力强。

     

    注:更多详细请参考https://blog.csdn.net/liuligui5200/article/details/79030676

    展开全文
  • C语言 sizeof操作符详解

    万次阅读 多人点赞 2012-02-09 21:33:59
    sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“ 辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能详细的总结一下。 但当我总结的时候才发现,这个问题既可以简单,又可以复杂...

    sizeof,一个其貌不扬的家伙,引无数菜鸟竟折腰,小虾我当初也没少犯迷糊,秉着“
    辛苦我一个,幸福千万人”的伟大思想,我决定将其尽可能详细的总结一下。
    但当我总结的时候才发现,这个问题既可以简单,又可以复杂,所以本文有的地方并不
    适合初学者,甚至都没有必要大作文章。但如果你想“知其然,更知其所以然”的话,
    那么这篇文章对你或许有所帮助。
    菜鸟我对C++的掌握尚未深入,其中不乏错误,欢迎各位指正啊

    1. 定义:
    sizeof是何方神圣sizeof乃C/C++中的一个操作符(operator)是也,简单的说其作
    用就是返回一个对象或者类型所占的内存字节数。
    MSDN上的解释为:
    The sizeof keyword gives the amount of storage, in bytes, associated with a
    variable or a type (including aggregate types).
    This keyword returns a value of type size_t.
    其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一
    般定义为
    typedef unsigned int size_t;
    世上编译器林林总总,但作为一个规范,它们都会保证char、signed char和unsigned
    char的sizeof值为1,毕竟char是我们编程能用的最小数据类型。
    2. 语法:
    sizeof有三种语法形式,如下:
    1) sizeof( object ); // sizeof( 对象 );
    2) sizeof( type_name ); // sizeof( 类型 );
    3) sizeof object; // sizeof 对象;
    所以,
    int i;
    sizeof( i ); // ok
    sizeof i; // ok
    sizeof( int ); // ok
    sizeof int; // error
    既然写法3可以用写法1代替,为求形式统一以及减少我们大脑的负担,第3种写法,忘
    掉它吧!
    实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的
    不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以
    对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式
    进行计算。如:
    sizeof( 2 );// 2的类型为int,所以等价于 sizeof( int );
    sizeof( 2 + 3.14 ); // 3.14的类型为double,2也会被提升成double类型,所以等价
    于 sizeof( double );
    sizeof也可以对一个函数调用求值,其结果是函数返回类型的大小,函数并不会被调用
    ,我们来看一个完整的例子:
    char foo()
    {
    printf("foo() has been called./n");
    return 'a';
    }
    int main()
    {
    size_t sz = sizeof( foo() ); // foo() 的返回值类型为char,所以sz = sizeof(
    char ),foo()并不会被调用
    printf("sizeof( foo() ) = %d/n", sz);
    }
    C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算s
    izeof值,即下面这些写法都是错误的:
    sizeof( foo );// error
    void foo2() { }
    sizeof( foo2() );// error
    struct S
    {
    unsigned int f1 : 1;
    unsigned int f2 : 5;
    unsigned int f3 : 12;
    };
    sizeof( S.f1 );// error
    3. sizeof的常量性
    sizeof的计算发生在编译时刻,所以它可以被当作常量表达式使用,如:
    char ary[ sizeof( int ) * 10 ]; // ok
    最新的C99标准规定sizeof也可以在运行时刻进行计算,如下面的程序在Dev-C++中可以
    正确执行:
    int n;
    n = 10; // n动态赋值
    char ary[n]; // C99也支持数组的动态定义
    printf("%d/n", sizeof(ary)); // ok. 输出10
    但在没有完全实现C99标准的编译器中就行不通了,上面的代码在VC6中就通不过编译。
    所以我们最好还是认为sizeof是在编译期执行的,这样不会带来错误,让程序的可移植
    性强些。
    4. 基本数据类型的sizeof
    这里的基本数据类型指short、int、long、float、double这样的简单内置数据类型,
    由于它们都是和系统相关的,所以在不同的系统下取值可能不同,这务必引起我们的注
    意,尽量不要在这方面给自己程序的移植造成麻烦。
    一般的,在32位编译环境中,sizeof(int)的取值为4。
    5. 指针变量的sizeof
    学过数据结构的你应该知道指针是一个很重要的概念,它记录了另一个对象的地址。既
    然是来存放地址的,那么它当然等于计算机内部地址总线的宽度。所以在32位计算机中
    ,一个指针变量的返回值必定是4(注意结果是以字节为单位),可以预计,在将来的6
    4位系统中指针变量的sizeof结果为8。
    char* pc = "abc";
    int* pi;
    string* ps;
    char** ppc = &pc;
    void (*pf)();// 函数指针
    sizeof( pc ); // 结果为4
    sizeof( pi ); // 结果为4
    sizeof( ps ); // 结果为4
    sizeof( ppc ); // 结果为4
    sizeof( pf );// 结果为4
    指针变量的sizeof值与指针所指的对象没有任何关系,正是由于所有的指针变量所占内
    存大小相等,所以MFC消息处理函数使用两个参数WPARAM、LPARAM就能传递各种复杂的消
    息结构(使用指向结构体的指针)。
    6. 数组的sizeof
    数组的sizeof值等于数组所占用的内存字节数,如:
    char a1[] = "abc";
    int a2[3];
    sizeof( a1 ); // 结果为4,字符 末尾还存在一个NULL终止符
    sizeof( a2 ); // 结果为3*4=12(依赖于int)
    一些朋友刚开始时把sizeof当作了求数组元素的个数,现在,你应该知道这是不对的,
    那么应该怎么求数组元素的个数呢Easy,通常有下面两种写法:
    int c1 = sizeof( a1 ) / sizeof( char ); // 总长度/单个元素的长度
    int c2 = sizeof( a1 ) / sizeof( a1[0] ); // 总长度/第一个元素的长度
    写到这里,提一问,下面的c3,c4值应该是多少呢
    void foo3(char a3[3])
    {
    int c3 = sizeof( a3 ); // c3 ==
    }
    void foo4(char a4[])
    {
    int c4 = sizeof( a4 ); // c4 ==
    }
    也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。这里函数参数a3已不
    再是数组类型,而是蜕变成指针,相当于char* a3,为什么仔细想想就不难明白,我
    们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的
    ,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为
    4。
    7. 结构体的sizeof
    这是初学者问得最多的一个问题,所以这里有必要多费点笔墨。让我们先看一个结构体

    struct S1
    {
    char c;
    int i;
    };
    问sizeof(s1)等于多少聪明的你开始思考了,char占1个字节,int占4个字节,那么
    加起来就应该是5。是这样吗你在你机器上试过了吗也许你是对的,但很可能你是错
    的!VC6中按默认设置得到的结果为8。
    Why为什么受伤的总是我
    请不要沮丧,我们来好好琢磨一下sizeof的定义——sizeof的结果等于对象或者类型所
    占的内存字节数,好吧,那就让我们来看看S1的内存分配情况:
    S1 s1 = { 'a', 0xFFFFFFFF };
    定义上面的变量后,加上断点,运行程序,观察s1所在的内存,你发现了什么
    以我的VC6.0为例,s1的地址为0x0012FF78,其数据内容如下:
    0012FF78: 61 CC CC CC FF FF FF FF
    发现了什么怎么中间夹杂了3个字节的CC看看MSDN上的说明:
    When applied to a structure type or variable, sizeof returns the actual siz
    e, which may include padding bytes inserted for alignment.
    原来如此,这就是传说中的字节对齐啊!一个重要的话题出现了。
    为什么需要字节对齐计算机组成原理教导我们这样有助于加快计算机的取数速度,否
    则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数
    据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,
    让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个
    数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。
    让我们交换一下S1中char与int的位置:
    struct S2
    {
    int i;
    char c;
    };
    看看sizeof(S2)的结果为多少,怎么还是8再看看内存,原来成员c后面仍然有3个填
    充字节,这又是为什么啊别着急,下面总结规律。

    字节对齐的细节和编译器实现相关,但一般而言,满足三个准则:
    1) 结构体变量的首地址能够被其最宽基本类型成员的大小所整除;
    2) 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,
    如有需要编译器会在成员之间加上填充字节(internal adding);
    3) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最
    末一个成员之后加上填充字节(trailing padding)。
    对于上面的准则,有几点需要说明:
    1) 前面不是说结构体成员的地址是其大小的整数倍,怎么又说到偏移量了呢因为有
    了第1点存在,所以我们就可以只考虑成员的偏移量,这样思考起来简单。想想为什么。

    结构体某个成员相对于结构体首地址的偏移量可以通过宏offsetof()来获得,这个宏也
    在stddef.h中定义,如下:
    #define offsetof(s,m) (size_t)&(((s *)0)->m)
    例如,想要获得S2中c的偏移量,方法为
    size_t pos = offsetof(S2, c);// pos等于4
    2) 基本类型是指前面提到的像char、short、int、float、double这样的内置数据类型
    ,这里所说的“数据宽度”就是指其sizeof的大小。由于结构体的成员可以是复合类型
    ,比如另外一个结构体,所以在寻找最宽基本类型成员时,应当包括复合类型成员的子
    成员,而不是把复合成员看成是一个整体。但在确定复合类型成员的偏移位置时则是将
    复合类型作为整体看待。
    这里叙述起来有点拗口,思考起来也有点挠头,还是让我们看看例子吧(具体数值仍以
    VC6为例,以后不再说明):
    struct S3
    {
    char c1;
    S1 s;
    char c2
    };
    S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,
    所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4整
    除,整个sizeof(S3)的值也应该被4整除。
    c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个
    准则,所以其大小为8,偏移量为4,c1与s之间便需要3个填充字节,而c2与s之间就不需
    要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补
    上3个填充字节。最后得到sizeof(S3)的值为16。
    通过上面的叙述,我们可以得到一个公式:
    结构体的大小等于最后一个成员的偏移量加上其大小再加上末尾的填充字节数目,即:

    sizeof( struct ) = offsetof( last item ) + sizeof( last item ) + sizeof( tr
    ailing padding )

    到这里,朋友们应该对结构体的sizeof有了一个全新的认识,但不要高兴得太早,有
    一个影响sizeof的重要参量还未被提及,那便是编译器的pack指令。它是用来调整结构
    体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以
    直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n ),n为字节对齐
    数,其取值为1、2、4、8、16,默认是8,如果这个值比结构体成员的sizeof值小,那么
    该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,
    公式如下:
    offsetof( item ) = min( n, sizeof( item ) )
    再看示例:
    #pragma pack(push) // 将当前pack设置压栈保存
    #pragma pack(2)// 必须在结构体定义之前使用
    struct S1
    {
    char c;
    int i;
    };
    struct S3
    {
    char c1;
    S1 s;
    char c2
    };
    #pragma pack(pop) // 恢复先前的pack设置
    计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)
    等于6,能够被2整除,所以整个S1的大小为6。
    同样,对于sizeof(S3),s的偏移量为2,c2的偏移量为8,加上sizeof(c2)等于9,不能
    被2整除,添加一个填充字节,所以sizeof(S3)等于10。
    现在,朋友们可以轻松的出一口气了,:)
    还有一点要注意,“空结构体”(不含数据成员)的大小不为0,而是1。试想一个“不
    占空间”的变量如何被取地址、两个不同的“空结构体”变量又如何得以区分呢于是
    ,“空结构体”变量也得被存储,这样编译器也就只能为其分配一个字节的空间用于占
    位了。如下:
    struct S5 { };
    sizeof( S5 ); // 结果为1

    8. 含位域结构体的sizeof
    前面已经说过,位域成员不能单独被取sizeof值,我们这里要讨论的是含有位域的结构
    体的sizeof,只是考虑到其特殊性而将其专门列了出来。
    C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,
    允许其它类型类型的存在。
    使用位域的主要目的是压缩存储,其大致规则为:
    1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字
    段将紧邻前一个字段存储,直到不能容纳为止;
    2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字
    段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
    3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方
    式,Dev-C++采取压缩方式;
    4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
    5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。

    还是让我们来看看例子。
    示例1:
    struct BF1
    {
    char f1 : 3;
    char f2 : 4;
    char f3 : 5;
    };
    其内存布局为:
    |_f1__|__f2__|_|____f3___|____|
    |_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|
    0 3 7 8 1316
    位域类型为char,第1个字节仅能容纳下f1和f2,所以f2被压缩到第1个字节中,而f3只
    能从下一个字节开始。因此sizeof(BF1)的结果为2。
    示例2:
    struct BF2
    {
    char f1 : 3;
    short f2 : 4;
    char f3 : 5;
    };
    由于相邻位域类型不同,在VC6中其sizeof为6,在Dev-C++中为2。
    示例3:
    struct BF3
    {
    char f1 : 3;
    char f2;
    char f3 : 5;
    };
    非位域字段穿插在其中,不会产生压缩,在VC6和Dev-C++中得到的大小均为3。
    9. 联合体的sizeof
    结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个
    联合体的sizeof也就是每个成员sizeof的最大值。结构体的成员也可以是复合类型,这
    里,复合类型成员是被作为整体考虑的。
    所以,下面例子中,U的sizeof值等于sizeof(s)。
    union U
    {
    int i;
    char c;
    S1 s;
    };

    展开全文
  • web.xml的加载过程配置详解

    万次阅读 多人点赞 2017-12-02 09:24:31
    一:web.xml加载过程  简单说一下,web.xml的加载过程。当我们启动一个WEB项目容器时,容器包括(JBoss,Tomcat等)。首先会去读取web.xml配置文件里的配置,当这一步骤没有出错并且完成之后,项目才能正常的被启动...
  • NSGA2算法中文详解与MATLAB实现整理

    千次阅读 2019-03-07 20:55:25
    NSGA2算法 NSGA-II多目标遗传算法概述 http://www.omegaxyz.com/2017/04/14/nsga-iiintro/ NSGA2算法MATLAB实现(能够自定义优化函数) ... NSGA2算法特征选择MATLAB实现(多目标) http://www.omegaxyz.co...
  • ViewPager 详解(一)---基本入门

    万次阅读 多人点赞 2014-08-09 09:48:01
    前言:这两天研究研究ViewPager滚动功能,现在很多的app都有用到这个功能,我们的大虾米也有这个模块。要研究就彻底的研究研究,我从不满足于一个功能...1、《ViewPager 详解(一)---基本入门》 2、《ViewPager 详...
  • 博客文章《完成端口详解》配套代码

    千次下载 热门讨论 2011-10-31 17:50:38
    这份代码是我博客里的文章《完成端口详解 - 手把手教你玩转网络编程系列之三》的配套代码 里面的代码包括VC++2008/VC++2010编写的完成端口服务器端的代码,还包括一个对服务器端进行压力测试的客户端,都是经过我...
  • STP详解(笔记)

    千次阅读 多人点赞 2019-06-30 09:26:58
    1、STP协议介绍 为了提高网络可好性,交换网络中通常会使用冗余链路,然而,冗余链路会交给交换网络带来环路风险,并导致广播风暴以及MAC地址表不稳定等问题,进而会影响到用户的通信质量。生成树协议STP(spanning ...
  • 蓝桥杯历年省赛真题汇总及题目详解

    万次阅读 多人点赞 2019-03-30 12:26:33
    蓝桥杯历年决赛试题汇总及试题详解 2013年第四届蓝桥杯省赛真题详解 第四届蓝桥杯JavaA组题目解析 第四届蓝桥杯JavaB组题目解析 第四届蓝桥杯JavaC组题目解析 2014年第五届蓝桥杯省赛真题详解 第五届蓝桥杯...
  • Maven之(六)setting.xml配置文件详解

    万次阅读 多人点赞 2016-05-24 09:51:24
    鉴于CSDN对**版权保护的不作为**以及落后的运营手段,本博客将于近期关闭,并清空全部文章。 原有文章将会经过再次的校对、整理,转移至本人在**简书**的[博客空间](https://www.jianshu.com/u/3ec23ef9a408... ...

空空如也

1 2 3 4 5 ... 20
收藏数 872,005
精华内容 348,802
关键字:

详解