Osheep

时光不回头,当下最重要。

linux c/c++知识点整理(六)

51、对称加密算法和非对称加密算法

       对称加密才用了对称密码编码技术,它的特点是文件加密和解密使用相同的密钥,即加密密钥也可以用解密密钥,这就是对称加密算法,常见的有:DES、IDEA。
       非对称加密算法需要两个密钥:公开密钥和私有密钥,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;反之,则用对应的公开密钥解密。非对称加密不适合对文件加密,只适合对少量数据进行加密,典型的应用是数字签名。

52、volatile关键字的作用

       volatile变量是随时可能发生变化的,它告诉编译器,与volatile变量有关的运算,不要进行任何优化,每次读取volatile变量时都重新从内存读取。

53、c++中动态联编和静态联编

       静态联编说的是在编译时就已经确定好了调用和被调用两者的关系;
       动态联编说的是程序在运行时才确定调用者和被调用者的关系,典型的应用是虚函数实现的多态性。

54、深拷贝和浅拷贝

       浅拷贝是指将对象内的数据完全一致的复制;
       深拷贝不是这样,它可以将内部的数据按照需要用特殊的方法拷贝,比如说对象内部有一个动态数组,浅拷贝只拷贝指针,而深拷贝则重新申请空间将数据复制过来。

55、什么是柔性数组?

       数组大小待定的数组就是柔性数组。
       一般结构体的最后一个元素可以是大小未知的数组。

56、库函数和系统调用的区别?

       库函数调用时面向应用开发的,与系统无关,移植性好。
       系统调用是面向底层,偏向硬件,系统内核软中断实现,移植性差,系统调用是用户程序和内核交互的接口,系统调用的过程如下:

  • 执行用户程序
  • 根据glibc的函数实现,取得系统调用号,并执行int$0x80产生中断
  • 进行地址空间的转换和堆栈的切换,执行SAVE _ALL(进入内核模式)
  • 进行中断处理,根据系统调用表调用内核函数
  • 执行内核函数
  • 执行RESTORE_ALL并返回用户模式
    系统调用比库函数调用快。

    57、构造函数里面”初始化列表”和”赋值”的区别

           对于内置类型来说,没有区别,对于非内置类型则有区别,如下:
           初始化列表只会调用一次构造函数,而赋值会先调用构造,再调用一次赋值函数,什么情况下只能使用初始化列表:

  • 没有默认构造函数的类;
  • 类中存在const成员或者引用类型的成员(它们只能被初始化);

    58、为什么要字节对齐?

           自然对齐:一个变量的内存正好是它长度的整数倍。
           需要字节对齐的根本原因在于CPU的效率问题,假设32位机器上int型变量地址是0x00000002,那么CPU取值时需要访问两次内存,一次是0x00000002-0x00000003的short,然后是0x00000004-0x00000005的short,而如果该int型变量的地址是0x00000003,那么CPU则要访问3次内存,即char-short-char,而如果变量是自然对齐的,则CPU访问一次内存就够了。

      struct stu
      {
          char sex;
          int length;
          char name[10];
      };

    sizeof(struct stu) = 20;//结构体中每个数据类型都要对齐
    什么情况下需要手动设置对齐:

  • 设计不同CPU下的通信协议(设计一个结构体,32位和64位都用时)
  • 编写硬件驱动程序时寄存器的结构
    手动设置对齐方式有两种:
  • 代码里添加预编译标识
    #pragma pack(n)
    #pragma pack()
  • GNU编译时
    #define GNUC_PACKED__attribut__((packed))

    59、浅谈僵尸进程

           僵尸进程:当子进程退出时,父进程没有调用wait函数或者waitpid()函数等待子进程结束,又没有显式忽略SIGCHLD信号,那么它将一直保持在僵尸状态,如果这时父进程结束了,init进程会自动接收这个子进程,为它收尸,但如果父进程是一个循环,不会结束,那么子进程就会一直保持僵死状态。
           进程状态:
    僵尸|休眠|不可中断的休眠|运行|停止式跟踪
    Z |S |D |R |T
           补救办法:杀死僵尸进程的父进程,让init进程来接手,清理掉子进程这个僵尸进程。
           僵尸进程的状态:一个进程在调用exit()函数结束时,并没有真正的被销毁,而是留下一个称为僵尸进程的数据结构,僵尸进程放弃了几乎所有的内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保持一个位置,记载该进程的退出状态等信息。
           避免僵尸进程的方法:

  • 使用signal函数忽略SIGCHLD信号
  • 调用wait或者waitpid()函数
  • fork两次,父进程fork子进程后继续执行,子进程fork一个孙进程后退出,此时孙进程会被init进程接管,避免僵尸进程,当然子进程的退出还是要进行处理的。

    60、fork函数浅析

           pid_t fork();
           返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程的进程id,否则,出错返回-1.
           子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。
           注意:子进程拥有的是副本,它跟父进程之间是不共享这些存储空间(但是共享代码段)的,因此子进程拥有独立的地址空间。
           fork可能出错的原因:

  • 当前进程数量已经达到了系统规定的上限;
  • 系统内存不足;
点赞