图文并茂,一文讲透C语言结构体内存对齐

2023-05-16

面试官:你知道C语言的结构体对齐吗? 

应聘者:听说过……平时很少关注 

……

面试官:好吧,那回去等通知吧 

 

C语言结构体对齐问题,是面试必备问题。

本文,除了用图解的方式讲清楚结构体知识点外,还将为你解答以下问题:

  • 为什么会有结构体内存对齐?

  • 结构体怎么对齐?

  • 学习结构体对齐有什么用?

  • 结构体对齐有没有实际应用?

 


▍结构体内存对齐的原因

一句话,为了提高效率,这个跟芯片设计有关。

自从我们刚学习编程开始,就会接触到例如字、双字、四字等概念这里涉及到内存边界问题,它们的地址分别是可被2/4/8整除的。另外,在汇编中,不同长度的内存访问会用到不同的汇编指令。

如果,一块内存在地址上随便放的,CPU有可能就会用到多条指令来访问,这就会降低效率。

对于32位系统,如下图的A可能需要2条指令访问,而B只需1条指令。


▍结构体内存对齐的规则

1. C语言基本类型的大小

不要瞎猜,直接上代码。每个平台都不一样,请读者自行测试,以下我是基于Windows上MinGW的GCC测的。

#define BASE_TYPE_SIZE(t)   printf("%12s : %2d Byte%s\n", #t, sizeof(t), (sizeof(t))>1?"s":"")void base_type_size(void){    BASE_TYPE_SIZE(void);    BASE_TYPE_SIZE(char);    BASE_TYPE_SIZE(short);    BASE_TYPE_SIZE(int);    BASE_TYPE_SIZE(long);    BASE_TYPE_SIZE(long long);    BASE_TYPE_SIZE(float);    BASE_TYPE_SIZE(double);    BASE_TYPE_SIZE(long double);    BASE_TYPE_SIZE(void*);    BASE_TYPE_SIZE(char*);    BASE_TYPE_SIZE(int*);        typedef struct     {    }StructNull;    BASE_TYPE_SIZE(StructNull);    BASE_TYPE_SIZE(StructNull*);}

结果是:

​​​​​​​

        void :  1 Byte        char :  1 Byte       short :  2 Bytes         int :  4 Bytes        long :  4 Bytes   long long :  8 Bytes       float :  4 Bytes      double :  8 Bytes long double : 12 Bytes       void* :  4 Bytes       char* :  4 Bytes        int* :  4 Bytes  StructNull :  0 Byte StructNull* :  4 Bytes

这些内容不用记住,不同平台是不一样的,使用之前,一定要亲自测试验证下,但是可以总结出以下信息:

  • void类型不是空的,占一个字节

  • long不一定比int大

  • C语言空结构体的大小为0(注意:C++的为1)

  • 不管什么类型,指针都是相同大小的

     

2. C语言结构体的内存对齐

我先看个例子:​​​​​​​


#define offset(type, member)      (size_t)&(((type *)0)->member)
#define STRUCT_E_ADDR(s,e)          printf("%5s size = %2d %16s addr: %p\n", #s, sizeof(s), #s"."#e, &s.e)
#define STRUCT_E_OFFSET(s,e)        printf("%5s size = %2d %16s offset: %2d\n", #s, sizeof(s), #s"."#e, offset(__typeof__(s),e))
#define STRUCT_E_ADDR_OFFSET(s,e)   printf("%5s size = %2d %16s addr: %p, offset: %2d\n", #s, sizeof(s), #s"."#e, &s.e, offset(__typeof__(s),e))

typedef struct 
{
    int e_int;
    char e_char;
}S1;
S1 s1;
STRUCT_E_ADDR_OFFSET(s1, e_int);
STRUCT_E_ADDR_OFFSET(s1, e_char);
typedef struct 
{
    int e_int;
    double e_double;
}S11;
S11 s11; 
STRUCT_E_ADDR_OFFSET(s11, e_int);
STRUCT_E_ADDR_OFFSET(s11, e_double);

 

咦……这宏定义是啥意思?传送门:《基于C99规范,最全C语言预处理知识总结

输出结果:​​​​​​​

   s1 size =  8         s1.e_int addr: 0028FF28, offset:  0   s1 size =  8        s1.e_char addr: 0028FF2C, offset:  4  s11 size = 16        s11.e_int addr: 0028FF18, offset:  0  s11 size = 16     s11.e_double addr: 0028FF20, offset:  8

结论1:一般情况下,结构体所占的内存大小并非元素本身大小之和。

结论2:不严谨地,结构体内存的大小按最大元素大小对齐。

继续看例子:​​​​​​​

    typedef struct     {        int e_int;        long double e_ld;    }S12;
    typedef struct     {        long long e_ll;        long double e_ld;    }S13;
    typedef struct     {        char e_char;        long double e_ld;    }S14;
    S12 s12;    S13 s13;    S14 s14;    STRUCT_E_ADDR_OFFSET(s12, e_int);    STRUCT_E_ADDR_OFFSET(s12, e_ld);    STRUCT_E_ADDR_OFFSET(s13, e_ll);    STRUCT_E_ADDR_OFFSET(s13, e_ld);    STRUCT_E_ADDR_OFFSET(s14, e_char);    STRUCT_E_ADDR_OFFSET(s14, e_ld);

输出结果:​​​​​​​

  s12 size = 16        s12.e_int addr: 0028FF08, offset:  0  s12 size = 16         s12.e_ld addr: 0028FF0C, offset:  4  s13 size = 24         s13.e_ll addr: 0028FEF0, offset:  0  s13 size = 24         s13.e_ld addr: 0028FEF8, offset:  8  s14 size = 16       s14.e_char addr: 0028FEE0, offset:  0  s14 size = 16         s14.e_ld addr: 0028FEE4, offset:  4

出现问题了,你看s12和s14,sizeof(long long)应该是12,按结论而推断sizeof(s12)和sizeof(s13)应该都是24。

这里跟平台和编译器的一个模数有关。

对结论2修正:结构体内存大小应按最大元素大小对齐,如果最大元素大小超过模数,应按模数大小对齐。

额外再送一条结论:如果结构体的最大元素大小超过模数,结构体的起始地址是可以被模数整除的。如果,最大元素大小没有超过模数大小,那它的起始地址是可以被最大元素大小整除

那么,这个模数是什么?

每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。

网上流传一个表:

平台

长度/模数

char

short

int

long

float

double

long long

long double

Win-32

长度

1

2

4

4

4

8

8

8

模数

1

2

4

4

4

8

8

8

Linux-32

长度

1

2

4

4

4

8

8

12

模数

1

2

4

4

4

4

4

4

Linux-64

长度

1

2

4

8

4

8

8

16

模数

1

2

4

8

4

8

8

16

本文的的例子我用的是MinGW32的GCC来测试,你猜符合上表的哪一项?

别急,再看一个例子:​​​​​​​

    typedef struct     {        int e_int;        double e_double;    }S11;    S11 s11;    STRUCT_E_ADDR_OFFSET(s11, e_int);    STRUCT_E_ADDR_OFFSET(s11, e_double);

结果是:​​​​​​​

  s11 size = 16        s11.e_int addr: 0028FF18, offset:  0  s11 size = 16     s11.e_double addr: 0028FF20, offset:  8

很明显,上表没有一项完全对应得上的。简单汇总以下我测试的结果:

长度/模数

char

short

int

long

float

double

long long

long double

长度

1

2

4

4

4

8

8

12

模数

1

2

4

4

4

8

8

8

所以,再强调一下:因为环境的差异,在你参考使用之前,请自行测试一下。

另外,提一下:这个模数是可以改变的,可以用预编译命令#pragma pack(n),n=1,2,4,8,16来改变这一系数,其中的n就是你要指定的“对齐系数”。

例如​​​​​​​

#pragma pack(1)typedef struct {    char e_char;    long double e_ld;}S14;#pragma pack()

#pragma是啥玩意?有兴趣可以看看:《基于C99规范,最全C语言预处理知识总结

好了,我们继续,这似乎没啥技术含量,我们提升下难度:​​​​​​​

    typedef struct     {        int e_int;        char e_char1;        char e_char2;    }S2;
    typedef struct     {        char e_char1;        int e_int;        char e_char2;    }S3;    S2 s2;    S3 s3;

你觉得这俩结构体所占内存是一样大吗?那你就错了:

​​​​​​​

   s2 size =  8         s2.e_int addr: 0028FED4, offset:  0   s2 size =  8       s2.e_char1 addr: 0028FED8, offset:  4   s2 size =  8       s2.e_char2 addr: 0028FED9, offset:  5   s3 size = 12       s3.e_char1 addr: 0028FEC4, offset:  0   s3 size = 12         s3.e_int addr: 0028FEC8, offset:  4   s3 size = 12       s3.e_char2 addr: 0028FECC, offset:  8

why?

上个图先看看,它们内存是怎么对齐的:

我们套一遍那几条结论就可以知道:

理解按最大元素大小或模数对齐,就可以看到S2的内存分布;

对于S3,e_int的位置地址,肯定是要按int的大小对齐的(地址可被int大小整除),这样才能提高访问效率。同时,这导致了很大的内存浪费。

以上例子,我们看到挨在一起的两个char会放在同一个对齐单元,如果挨在一起的short和char会不会放一起?​​​​​​​

    typedef struct     {        char e_char1;        short e_short;        char e_char2;        int e_int;        char e_char3;    }S4;    S4 s4;    STRUCT_E_ADDR_OFFSET(s4, e_char1);    STRUCT_E_ADDR_OFFSET(s4, e_short);    STRUCT_E_ADDR_OFFSET(s4, e_char2);    STRUCT_E_ADDR_OFFSET(s4, e_int);    STRUCT_E_ADDR_OFFSET(s4, e_char3);

输出结果:​​​​​​​

   s4 size = 16       s4.e_char1 addr: 0028FEB4, offset:  0   s4 size = 16       s4.e_short addr: 0028FEB6, offset:  2   s4 size = 16       s4.e_char2 addr: 0028FEB8, offset:  4   s4 size = 16         s4.e_int addr: 0028FEBC, offset:  8   s4 size = 16       s4.e_char3 addr: 0028FEC0, offset: 12

得出一个经验:

我们在定义结构体的时候,尽量把大小相同或相近的元素放一起,以减少结构体占用的内存空间。

再来一个问题:

结构体套着另一个结构体怎么计算?

 typedef struct 
    {
        int e_int;
        char e_char;
    }S1;
   typedef struct 
    {
        S1 e_s;
        char e_char;
    }SS1;

    typedef struct 
    {
        short e_short;
        char e_char;
    }S6;

    typedef struct 
    {
        S6 e_s;
        char e_char;
    }SS2; 
    
    SS1 ss1;
    STRUCT_E_ADDR_OFFSET(ss1, e_s);
    STRUCT_E_ADDR_OFFSET(ss1, e_char);

    SS2 ss2;
    STRUCT_E_ADDR_OFFSET(ss2, e_s);
    STRUCT_E_ADDR_OFFSET(ss2, e_char);

 

​​​​​​​

输出结果:​​​​​​​

  ss1 size = 12          ss1.e_s addr: 0028FE94, offset:  0  ss1 size = 12       ss1.e_char addr: 0028FE9C, offset:  8  ss2 size =  6          ss2.e_s addr: 0028FE8E, offset:  0  ss2 size =  6       ss2.e_char addr: 0028FE92, offset:  4

得出结论:结构体内的结构体,结构体内的元素并不会和结构体外的元素合并占一个对齐单元。

温馨提示:大家不要刻意去记这些结论,动手去试试并思考下效果会更好。

 

3. 联合体union的内存对齐

直接上代码:​​​​​​​

    typedef union 
    {
        char e_char;
        int e_int;
    }U1;

    U1 u1;
    STRUCT_E_ADDR(u1, e_char);
    STRUCT_E_ADDR(u1, e_int);

输出结果:

​​​​​​​

   u1 size =  4        u1.e_char addr: 0028FF2C   u1 size =  4         u1.e_int addr: 0028FF2C

从教科书上,我都可以理解,联合体里面的元素,实际上共享同一个空间。

那么,union跟struct结合呢?​​​​​​​

    typedef struct
    {
        int e_int1; 
        union
        {
            char ue_chars[9]; 
            int ue_int;
        }u;
        double e_double; 
        int e_int2; 
    }SU2;
    SU2 su2;
    STRUCT_E_ADDR_OFFSET(su2, e_int1);
    STRUCT_E_ADDR_OFFSET(su2, u.ue_chars);
    STRUCT_E_ADDR_OFFSET(su2, u.ue_int);
    STRUCT_E_ADDR_OFFSET(su2, e_double);
    STRUCT_E_ADDR_OFFSET(su2, e_int2)

 

输出:​​​​​​​

  su2 size = 32       su2.e_int1 addr: 0028FEF8, offset:  0  su2 size = 32   su2.u.ue_chars addr: 0028FEFC, offset:  4  su2 size = 32     su2.u.ue_int addr: 0028FEFC, offset:  4  su2 size = 32     su2.e_double addr: 0028FF08, offset: 16  su2 size = 32       su2.e_int2 addr: 0028FF10, offset: 24

实际上跟结构体类似,也没有特别的规则。

顺便提一下,使用union时,要留意平台的大小端问题。

大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放;这和我们的阅读习惯一致。 

小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。

百度百科——大小端模式

怎么获知自己使用的平台的大小端?Linux有个方法

    static union { 
        char c[4]; 
        unsigned long l; 
    } endian_test = { { 'l', '?', '?', 'b' } };
    #define ENDIANNESS ((char)endian_test.l)

    printf("ENDIANNESS: %c\n", ENDIANNESS);

4. 位域(Bitfield)的相关

位域在本文没什么好探讨的,在结构体对齐方面没什么特别的地方。

直接看个测试代码,就可以明白:

void bitfield_type_size(void)
{
    typedef struct
    {
        char bf1:1;
        char bf2:1;
        char bf3:1;
        char bf4:3;
    }SB1;

    typedef struct
    {
        char bf1:1;
        char bf2:1;
        char bf3:1;
        char bf4:7;
    }SB2;

    typedef struct
    {
        char bf1:1;
        char bf2:1;
        char bf3:1;
        int  bfint:1;
    }SB3;

    typedef struct
    {
        char bf1:1;
        char bf2:1;
        int  bfint:1;
        char bf3:1;
    }SB4;

    SB1 sb1;
    SB2 sb2;
    SB3 sb3;
    SB4 sb4;
    VAR_ADDR(sb1);
    VAR_ADDR(sb2);
    VAR_ADDR(sb3);
    VAR_ADDR(sb4);
    
    typedef struct
    {
        unsigned char bf1:1;
        unsigned char bf2:1;
        unsigned char bf3:1;
        unsigned char bf4:3;
    }SB11;

    typedef union 
    {
        SB11 sb1;
        unsigned char  e_char;
    }UB1;
    UB1 ub1;

    STRUCT_E_ADDR_OFFSET(ub1, sb1);
    STRUCT_E_ADDR_OFFSET(ub1, e_char);

    ub1.e_char = 0xF5;
    BITFIELD_VAL(ub1, e_char);
    BITFIELD_VAL(ub1, sb1.bf1);
    BITFIELD_VAL(ub1, sb1.bf2);
    BITFIELD_VAL(ub1, sb1.bf3);
    BITFIELD_VAL(ub1, sb1.bf4);
}

输出结果是:

  sb1 size =  1        sb1 addr: 0028FF2F  sb2 size =  2        sb2 addr: 0028FF2D  sb3 size =  8        sb3 addr: 0028FF24  sb4 size = 12        sb4 addr: 0028FF18  ub1 size =  1          ub1.sb1 addr: 0028FF17, offset:  0  ub1 size =  1       ub1.e_char addr: 0028FF17, offset:  0         ub1 :  1 Byte, ub1.e_char=0xF5         ub1 :  1 Byte, ub1.sb1.bf1=0x1         ub1 :  1 Byte, ub1.sb1.bf2=0x0         ub1 :  1 Byte, ub1.sb1.bf3=0x1         ub1 :  1 Byte, ub1.sb1.bf4=0x6

有几个点需要注意下:

  1. 内存的计算单位是byte,不是bit

  2. 结构体内即使有bitfield元素,其对齐规则还是按照基本类型来

  3. bitfield元素不能获得其地址(即程序中不能通过&取址)

 

5. 规则总结

首先,不推荐记忆这些条条框框的文字,以下内容仅供参考:

  1. 结构体的内存大小,并非其内部元素大小之和;

  2. 结构体变量的起始地址,可以被最大元素基本类型大小或者模数整除;

  3. 结构体的内存对齐,按照其内部最大元素基本类型或者模数大小对齐;

  4. 模数在不同平台值不一样,也可通过#pragma pack(n)方式去改变;

  5. 如果空间地址允许,结构体内部元素会拼凑一起放在同一个对齐空间;

  6. 结构体内有结构体变量元素,其结构体并非展开后再对齐;

  7. union和bitfield变量也遵循结构体内存对齐原则。

 


▍编程为什么要关注结构体内存对齐

也许你会问,结构体爱怎么对齐就怎么对齐,我管它干嘛!

1. 节省内存

在嵌入式软件开发中,特别是内存资源匮乏的小MCU,这个尤为重要。如果优化程序内存,使得MCU可以选更小的型号,对于大批量出货的产品,可以带来更高利润。

也许你还还感觉不到,上段代码:

    typedef struct 
    {
        int e_int;
        char e_char1;
        char e_char2;
    }S2;

    typedef struct 
    {
        char e_char1;
        int e_int;
        char e_char2;
    }S3;
    
    S2 s2[1024] = {0};
    S3 s3[1024] = {0};

   

s2的大小为8K,而s3的大小为12K,一放大,就有很明显的区别了。

2. union的内存对齐需要

对于同一个内存,有时为了满足不同的访问形式,定义一个联合体变量,或者一个结构体和联合体组合的变量。此时就要知道其内存结构是怎么分布的。

3. 内存拷贝

有时候,我们在通信数据接收处理时候,往往遇到,数组和结构体的搭配。

即,通信时候,通常使用数组参数形式接收,而处理的时候,按照预定义格式去访问处理。例如:

U8 comm_data[10];
typedef struct
{
    U8 id;
    U16 len;
    U8 data[6];
}FRAME;

FRAME* pFram = (FRAME*)comm_data;

此处,必须要理解这个FRAM的内存结构是怎么样的对齐规则。

4. 调试仿真时看压栈数据

在调试某些奇葩问题时,迫不得已,我们会研究函数跳转或者线程切换时的栈数据,遇到结构体内容,肯定要懂得其内存对齐方式才能更好地获得栈内信息。

 

当然,还有其他方面的原因,在此就不一一列举了。

 


▍结构体内存对齐实际应用

上面一个章节已经部分讲到这个结构体内存对齐的应用了,例如通信数据的处理等。另外,再举两个例子:

1. 内存的mapping

假设你要做一个烧录文件,你想往文件头空间128个字节内放一段项目信息(例如程序大小、CRC校验码、其他项目信息等)。第一反应,你会考虑用一个结构体,定义一段这样的数据,程序运行的时候也定义同样的结构体去读取这个内存。但是你需要知道结构体大小啊,这个结构体内存对齐的规则还是需要了解的。

2. 单片机寄存器的mapping

在写MCU驱动的时候,访问寄存器的方式有很多种,但是做到清晰明了,适配性好的,往往需要诸多考量。

直接通过整型指针指到特定地址去访问,是没有问题的,但是对于某一类型的寄存器,往往不是一个固定地址,其后面还有一堆子寄存器属性需要配置。每个地址都通过整型指针访问,那就很多很凌乱。

我们可以通过定义一个特定的结构体,用其指针直接mapping到寄存器的base地址。但是遇到有些地址是空的怎么办?甚至有些寄存器是32位的,有些16位,甚至8位的,各种参差不齐都在里面。

那就要考虑结构体内存对齐了,特别是结构体内有不同类型的元素。

这里只探讨应用场景,具体实现还要根据实际情况来定义。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

图文并茂,一文讲透C语言结构体内存对齐 的相关文章

  • C++之future和promise

    C 43 43 之future和promise future和promise的作用是在不同线程之间传递数据 使用指针也可以完成数据的传递 xff0c 但是指针非常危险 xff0c 因为互斥量不能阻止指针的访问 xff1b 而且指针的方式传递
  • linux常用小知识点

    答案linux考试题 1 在登录Linux时 xff0c 一个具有唯一进程ID号的shell将被调用 xff0c 这个ID是什么 b A NID B PID C UID C CID 答 xff1a w命令查看用户tty终端信息 ps ef
  • 无锁编程基础

    背景 我们处在技术快速发展的时代 xff0c 竞争变得前所未有的激烈 xff0c 不仅要十八般武艺俱全 xff0c 还得选对正确的技术 xff0c 跟上发展的脚步 xff0c 并贴上精研某个专业方向的标签 我们不仅要面对多线程和并发 xff
  • Linux网络相关概念和修改IP地址的方法

    网卡的命名规则 ifconfig xff1a 用于显示或设置网络设备 ens32 span class token punctuation span flags span class token operator 61 span span
  • 二维坦克大战游戏代码开发

    这是我实际面试中 xff0c 遇到的一个题目 xff0c 编写一个坦克大战游戏 一开始感觉懵 xff0c 后来代码写写就好了 include lt iostream gt include lt stdlib h gt include lt
  • 软件系统性能常识

    不管是系统设计人员 开发人员还是测试人员 xff0c 要构建高性能的系统 xff0c 对于系统性能的一些常用术语都不了解 xff0c 那是无从做起的 xff0c 这里主要介绍几个软件性能指标的术语及计算方法 xff0c 便以在性能优化及性能
  • Socket的三种轮询方式select、poll、epoll之间的区别

    select poll epoll之间的区别 搜狗面试 1 select 61 61 gt 时间复杂度O n 它仅仅知道了 xff0c 有I O事件发生了 xff0c 却并不知道是哪那几个流 xff08 可能有一个 xff0c 多个 xff
  • linux后端c++开发人员需要学习的技术栈

    数据结构和算法 学完之后要刷leetcode xff08 剑指offer xff09 计算机网络 tcp ip 协议栈 xff08 tcp ip详解 xff09 操作系统 进程和线程 并发 和锁 内存分布调度等等 xff08 深入理解操作系
  • 内核态和用户态的区别

    内核态和用户态的区别 当一个任务 进程 执行系统调用而陷入内核代码中执行时 xff0c 我们就称进程处于内核状态 此时处理器处于特权级 最高的 0级 内核代码 当进程处于内核态时 xff0c 执行的内核代码会使用当前的内核栈 每个进程都有自
  • Linux查找命令四剑客awk、sed、find(locate)、grep讲解

    目录 find命令 xff1a 一旦执行了chmod 000 那么如何恢复权限呢 xff1f 2 grep xff08 找文件内容 行操作 xff09 3 awk 4 sed 找文件内容 行操作 find命令 xff1a 1 find xf
  • go语言学习笔记,特点

    1 并发编程 Go语言在并发编程方面比绝大多数语言要简洁不少 xff0c 这一点是其最大亮点之一 xff0c 也是其未来进入高并发高性能场景的重要筹码 golang的并发执行单元是一种称为goroutine的协程 协程又称为微线程 xff0
  • 进程调度,一个调度器的自白

    进程调度 xff0c 一个调度器的自白 我是一个进程调度器 我的职责是调度计算机内所有的进程 xff0c 为他们分配 CPU 资源 1 批处理时代 想当初 xff0c 操作系统创造我时 xff0c 只是打算让我用 FCFS 调度算法 xff
  • 厉害了!除了find命令,还有这么多文件查找命令,高手必备!

    目录 1 locate 2 whereis 3 which 4 type 1 locate locate命令其实是 find name 的另一种写法 xff0c 但是要比后者快得多 xff0c 原因在于它不搜索具体目录 xff0c 而是搜索
  • 浅析Linux中的零拷贝技术

    浅析Linux中的零拷贝技术 目录 浅析Linux中的零拷贝技术 引文 什么是零拷贝技术 xff08 zero copy xff09 xff1f 使用 mmap 使用sendfile 使用splice 本文探讨Linux中 主要的几种零拷贝
  • Linux用户管理(Centos7)

    用户管理 用户命令 添加登录用户 xff1a 例 xff1a 添加一个名为harry的用户 xff0c 并使用bash作为登录的shell span class token punctuation span root 64 aws span
  • CPU明明8个核,网卡为啥拼命折腾一号核?

    中断机制 我是CPU一号车间的阿Q xff0c 我又来了 xff01 我们日常的工作就是不断执行代码指令 xff0c 不过这看似简单的工作背后其实也并不轻松 咱不能闷着头啥也不管一个劲的只管执行代码 xff0c 还得和连接在主板上的其他单位
  • 好久没出去面试了,没想到问这么难...

    好久没出去面试了 xff0c 没想到问这么难 1周前 不知道你们多长时间没有参加过面试了 xff0c 最近这段时间的面试 xff0c 真的是一个比一个严格 xff01 我昨天参加了一线大厂的技术面 xff0c 被问到了一些并发相关的问题 x
  • 救命,Linux正在吃掉我的内存!

    内存发现自己的空闲空间越来越少 xff0c 经过一番调查 xff0c 发现罪魁祸首居然是Linux老大 xff01 内存 xff1a Linux老大 xff0c 这也没几个程序在运行 xff0c 可是你为什么老是占用我的内存啊 xff0c
  • 太高效了!玩了这么久的Linux,居然不知道这7个终端快捷键!

    作为 Linux 用户 xff0c 大家肯定在 Linux 终端下敲过无数的命令 有的命令很短 xff0c 比如 xff1a ls cd pwd 之类 xff0c 这种命令大家毫无压力 但是 xff0c 有些命令就比较长了 xff0c 比如
  • 这样处理Shell脚本参数,爽多了!

    这样处理Shell脚本参数 xff0c 爽多了 xff01 在 shell必备基础知识 中说到了一些入口参数的基本使用 xff1a home shouwang test sh para1 para2 para3 0 1 2 3 脚本名 第一

随机推荐

  • 面试官:kill -9 进程杀不掉,怎么办?

    用ps和grep命令寻找僵尸进 ps A ostat ppid pid cmd grep e 39 Zz 39 命令注解 xff1a A 参数列出所有进程 o 自定义输出字段 我们设定显示字段为 stat xff08 状态 xff09 pp
  • GCC为何如此强大? 动态库与静态库

    做软件开发的读者 xff0c 应该对GCC都不会陌生 xff0c 之所以大家都能知道它 xff0c 了解它 xff0c 是因为它有许多特殊 强大的 功能 一 GCC发展史 GNU 项目计划的主要目的是创建一个名叫 GNU s Not Uni
  • 看完这篇操作系统,和面试官扯皮就没问题了。

    解释一下什么是操作系统 操作系统是运行在计算机上最重要的一种软件 xff0c 它管理计算机的资源和进程以及所有的硬件和软件 它为计算机硬件和软件提供了一种中间层 通常情况下 xff0c 计算机上会运行着许多应用程序 xff0c 它们都需要对
  • extern “C”的作用详解

    extern 34 C 34 的主要作用就是为了能够正确实现C 43 43 代码调用其他C语言代码 加上extern 34 C 34 后 xff0c 会指示编译器这部分代码按C语言 xff08 而不是C 43 43 xff09 的方式进行编
  • Linux 进程与程序区别与联系

    一 xff0c 什么是程序 xff1f 程序是完成特定任务的一系列指令集合 二 xff0c 什么是进程 xff1f 从用户的角度来看进程是程序的一次动态执行过程从操作系统的核心来看 xff0c 进程是操作系统分配的内存 CPU时间片等资源的
  • 软件包的管理(Centos7)

    软件包类型 xff1a rpm软件包的管理 xff1a rpm包格式说明 xff1a span class token punctuation span root 64 aws span class token operator span
  • unix环境编程1 环境变量

    预处理 编译 汇编 连接 cpu中有个MMU xff0c 内存处理单元 xff1a 它的作用是 1 处理物理内存与虚拟内存映射的关系 2 设置修改内存访问级别 xff08 0 3级 xff09 内核空间的访问级别为0 用户空间的访问级别为3
  • RSU NTP时间同步配置方式

    RSU NTP同步配时方式 RSU ntp同步配时是基于一个开源工具chrony实现的 xff0c 这个工具集成在RSU里面了 xff0c 网上也能搜索到教程 xff0c 以下是一个参考链接 xff1a Centos使用chrony做时间同
  • Linux回收子进程

    孤儿进程 孤儿进程 父进程先于子进程结束 xff0c 则子进程成为孤儿进程 xff0c 子进程的父进程成为init进程 xff0c 称为init进程领养孤儿进程 include lt stdio h gt include lt unistd
  • C++内存管理(超长,例子很详细,排版很好)

    导语 内存管理是C 43 43 最令人切齿痛恨的问题 xff0c 也是C 43 43 最有争议的问题 xff0c C 43 43 高手从中获得了更好的性能 xff0c 更大的自由 xff0c C 43 43 菜鸟的收获则是一遍一遍的检查代码
  • c++ string 的常用库函数的用法

    目录 一 初始化 二 获取长度 xff08 length size xff09 三 插入 xff08 insert xff09 四 替换 xff08 replace xff09 五 添加 xff08 append xff09 六 赋值 xf
  • linux学习笔记1

    shutdown 一分钟后关机 shutdown c 取消关机命令 shutdown r 重新启动系统 shutdown 43 10 十分钟后关机 ifconfig 查看 配置计算机当前的网卡配置信息 ping 地址 检测目标ip地址的连接
  • 一道爬楼梯的算法题

    一个小孩爬楼梯 xff0c 每次可以爬1个 2个或3个台阶 xff0c 编程求出这个小孩爬完10个台阶的楼梯一共有多少种走法 def main k 61 0 构建函数1 x 43 2 y 43 3 z 61 10 确定x取值范围 for x
  • 面试技术杂ji——需要解决的问题

    需要搞明白的几个问题 xff1a 1 3次握手和4次挥手 2 TCP与UDP的区别 3 如果TCP连接出现问题该如何排查 xff0c 说明排查的思路 连接断开或者出错 xff0c 会返回一个错误码 xff0c errorNo 最后一次系统调
  •  SHELL 脚本学习笔记

    第十四章 SHELL 脚本 终于到 shell 脚本这章了 xff0c 在以前笔者卖了好多关子说 shell 脚本怎么怎么重要 xff0c 确实 shell 脚本在 linux 系统管理员的运维工作中非常非常重要 下面笔者就带你正式进入 s
  • 软件定义汽车 新一代技术发展

    引言 作为一个技术的爱好者 xff0c 搞算法 xff0c 玩芯片 xff0c 攒系统 xff0c 并不只是工作 xff0c 也是自己所追求的很重要的部分 写这个系列 xff0c 是为了梳理这几年的所学 所思 所想 xff0c 从而形成一个
  • 解压缩 tar命令详解

    1 tar命令进行文档的归档和压缩 归档和压缩文件 归档和压缩文件的好处 xff1a 节约硬盘的资源 xff0c 加快文件传输速率 tar命令 作用 xff1a 打包 压缩文件 xff1b tar文件是把几个文件和 xff08 或 xff0
  • 华测导航GPCHC协议ROS驱动包,CGI610、410接收机,NavSatStatus、GPSFix和普通格式

    目录 一 消息类型1 1 sensor msgs NavSatFix1 2 sensor msgs NavSatStatus1 3 gps common GPSFix1 4 sensor msgs Imu 二 部分源码2 1 相关的依赖和库
  • 淡定地撸了一遍AUTOSAR的基本概念

    1 AUTOSAR的解决方案 之前的文章 老板说项目要上AUTOSAR xff0c 我慌得一批 讲到了 xff0c 面对日益复杂的汽车E E架构 xff0c 在欧洲大地上诞生的AUTOSAR组织 xff0c 提出了解决方案 而且做了标准化
  • 图文并茂,一文讲透C语言结构体内存对齐

    面试官 xff1a 你知道C语言的结构体对齐吗 xff1f 应聘者 xff1a 听说过 平时很少关注 面试官 xff1a 好吧 xff0c 那回去等通知吧 C语言结构体对齐问题 xff0c 是面试必备问题 本文 xff0c 除了用图解的方式