C++之基础总结

目录

  • POD类型
  • 左值和右值
  • 静态全局变量(static)
  • 类型转换
  • const/constexpr
    • const
    • constexpr
  • C++中的关键字
  • union
  • 基础知识点
  • 编译与函数参数入栈总结
  • 一些常见用法归纳:

POD类型

平凡的和标准布局的——貌似和深度探索C++对象模型中关于按位拷贝冲突

  • 平凡的定义:符合以下四点定义:是不是可以总结为:构造,析构,拷贝/移动构造/赋值运算符 都是自动生成,不包含虚函数/虚基类
    • 有平凡的构造和析构:即构造和析构什么都不干,而一旦定义了构造或析构,即使不含参数,实现为空,也不再平凡,需定义成default;一般默认生成即可
    • 平凡的拷贝构造和移动构造:平凡的拷贝构造等同于使用memcpy进行类型的构造;默认生成或显式定义成default
    • 平凡的拷贝赋值运算符和移动赋值运算符,这基本上同平凡的拷贝构造和平凡的移动构造类似
    • 不能包含虚函数和虚基类
  • 标准布局:
    • 所有非静态成员都有相同的访问权限
    • 类或结构体继承时,满足以下两种情况之一:就是非静态成员不能同时出现在基类和派生类中
      • 派生类中有非静态成员,且只有一个仅包含静态成员的基类
      • 基类有非静态成员,而派生类没有非静态成员
    • 类中第一个非静态成员的类型与其基类不同
    • 没有虚函数和虚基类
    • 所有非静态数据成员均符合标准布局类型,其基类也符合标准布局
  • pod类型相关的类模板工具 #include<type_traits>
    • template<typename T>struct std::is_trivial的成员value可以用于判断T类型是否是一个POD类型;除了类和结构体之外,is_trivial可以对内置的标量类型数据及数组类型进行判断
    • template<typename T>struct std::is_standard_layout的value可以判断类型是否是一个标准布局的类型
    • template<typename T>std::is_pod<T>::value可以判断一个类型是否是POD,T可以是基本类型
  • 使用POD类型有什么好处:
    • 提供对C内存布局兼容,C++程序和C函数进行相互操作,因为POD类型的数据在C与C++间的操作总是安全的
    • 字节赋值:可以安全的使用memset和memcpy对POD类型进行初始化和拷贝等操作
    • 保证了静态初始化的安全有效。静态初始化在很多时候能够提高程序的性能,而POD类型的对象初始化往往更简单—(比如放入目标文件的bss段,在初始化中直接赋值为0)。

左值和右值

  • 左值:可以取地址,有名字的就是左值,反之就是右值(更简单的,=左边的就是左值,右边的就是右值),调用一个返回引用的函数得到的是左值,其他返回类型得到右值,特别的,可以为返回类型是非常量引用的函数的结果赋值
  • 右值:C++11中的右值分为纯右值和将亡值
    • 纯右值:之前的右值概念
    • 将亡值:C++11中新增的跟右值引用相关的表达式,如返回右值引用T&&的函数返回值,或者转换为T&&的类型转换函数的返回值,std::move的返回值
  • 右值引用:对一个右值进行引用的类型;右值引用也必须立即初始化;右值引用是为了支持移动操作而引入的
    • 一般右值不具有名字,通常情况下只能从右值表达式获取其引用,如T&& t = ReturnRValue(); 函数返回的右值在表达式语句结束后生命就结束了,通过右值引用的声明,该右值又重获新生,其声明周期和右值引用类型变量t的生命周期一样,不过需要注意,能够声明右值引用t的前提是ReturnRvalue返回的是一个右值
    • 左值引用和右值引用都是都必须立即初始化,左值引用是具名变量值的引用,右值引用是不具名变量值的引用
    • 右值引用不能绑定到任何左值,只能绑定到一个将要销毁的对象,如int c; int &&d=c;是不能通过编译的
    • 左值引用是否可以绑定到右值?
    • 右值引用的来由从来就跟移动语义紧密相关,这是右值存在的最大价值之一
    • 为什么不使用常量右值引用?
      • 一. 右值引用主要是为了移动语义,而移动语义需要右值是可以被修改的;
      • 二,如果要引用右值且不可以更改,常量左值就足够了
T& e = ReturnRvalue();        // 编译错误
const T& f = ReturnRvalue();  // 编译成功,常量左值引用在C++98中是个万能的引用类型,可以接受非常量左值,常量左值,右值对其进行初始化,而且在使用右值对其进行初始化的时
                              // 候常量左值引用还可以像右值引用一样将右值的生命期延长。

所以说,在定义一个移动构造函数的时候,定义一个常量左值引用的拷贝构造函数,是一种非常安全的设计——移动不成还可以执行拷贝

const bool & judge = true;  // 
const bool judge2 = true;  
// 上面两条的区别就是:前者直接使用右值并为其续命,后者的右值在表达式结束后就销毁了
  • 判断是否是引用类型/左值引用/右值引用:#include<type_traits>,通过类模板的成员value获取
    • is_rvalue_reference
    • is_lvalue_reference
    • is_reference
  • std::move:并不能移动任何东西,只是将左值强制转成右值,从实现上看相当于static_cast<T&&>(lvalue)。注意:被转换的左值,其生命周期并没有随着左右值的转化而改变,就是说,lvalue的析构不能依赖于move的实现,所以要析构掉就要靠自己?

静态全局变量(static)

  • static修饰的全局变量的声明与定义同时进行,即当你在头文件中使用static声明了全局变量,同时它也被定义了,如果没有明确的值会赋值为0(NULL, “”),不像其他变量不明确
  • static变量只会被初始化一次,下次进来的时候不会重新执行,以此特性可以使用单例模式
  • static修饰的全局变量的作用域只能是本身的编译单元。在其他编译单元使用它时,只是简单的把其值复制给了其他编译单元,其他编译单元会另外开个内存保存它,在其他编译单元对它的修改并不影响本身在定义时的值。即在其他编译单元A使用它时,它所在的物理地址,和其他编译单元B使用它时,它所在的物理地址不一样,A和B对它所做的修改都不能传递给对方。这也是不能用extern修饰static变量的原因,extern修饰全局变量和函数,在其他文件中是通用的;这也是多个地方引用静态全局变量所在的头文件不会出现重定义错误的原因,因为在每个编译单元都对它开辟了额外的空间进行存储。
  • C++中,全局static变量和class的static成员在main之前先初始化,main之后销毁
  • 函数内的static变量在什么时候执行初始化?
    • 如果初始值是一个编译期常量,在函数的任何一行执行之前就已经初始化了
    • 如果初始值不是一个编译期常量,或者静态变量是一个拥有构造函数的对象,在执行期初始化,也就是函数第一次调用时初始化
  • static成员变量:
    • 类外定义static成员时不能重复static变量,该关键字只出现在类内部的声明中
    • 不能在类内部初始化静态成员,相反必须在类的外部定义和初始化每个静态成员
    • 类似于全局变量,静态数据成员定义于任何函数之外,因此一旦被定义,就存在于程序的整个生命周期
    • 类外定义时需要指定对象的类型,类名,作用域运算符及成员自己的名字

类型转换

  • 知识点:
    • 任何一个转型动作往往令编译器编译出运行期间执行代码——??
    • 显示转型可能发生拷贝——??
    • 显示转换会不会抛出异常——待验证
  • 转换符:
    • static_cast:强迫隐式转换,不包含底层const的任何具有明确定义的类型转换。——底层const也可以转啊,比如boost::simple_segregated_storage中的 nextof
      • 适用场合:编译器隐式执行的任何类型转换都可以由static_cast来完成
         a. 需要把一个较大的算术类型赋值给较小的类型
         b. 对于编译器无法自动执行的类型转换如:子类(指针)转成基类(指针)但不做运行时的检查,不如dynamic_cast安全。static_cast仅靠类型转换语句中提供的信息来进行转换,而dynamic_cast则会遍历整个类继承体系进行类型检查,因此dynamic_cast在执行效率要差一些。
         c. void* 转成具体结构,不同指针类型之间的转换使用static_cast<void*>作为桥梁
         d. int转成对应的枚举
         e. 将non-const转成const等,但不能将const转成non-const——不需要吧,non-const可以直接给const
         f. 针对右值引用的特许转换规则:虽然不能隐式的将一个左值转换为右值引用,但可以用static_cast显式地将一个左值转换为一个右值引用,也就是std::move的功能吧:static_cast<T&&>(t)
    • const_cast:只能改变底层const;因为不能把一个const对象赋给非const对象,通过该函数可进行转换:去const属性;
      • 适用场合:——待验证
         a. const_cast常常用于有函数重载的上下文中
         b. 去const属性
        const char * pc;
        char * p = const_cast<char*>(pc); //正确但通过p写值是未定义的行为
    • reinterpret_cast:通常为运算对象的位模式提供较低层次上的重新解释,执行低级转型,实际动作取决于编译器,这也表示他是不可移植的,转换结构几乎都是在执行期定义。
      • 要点:一个指向字符串的指针是如何地与一个指向整数的指针或者一个指向其他自定义类型对象的指针有所不同呢?从内存需求的观点来说并没有不同,它们三个都需要足够的内存来放置一个机器地址。指向不同类型各指针之间的差异,既不在其指针表示法不同,也不在其内容不同,而是其所寻址出来的对象类型不同,也就是说,指针类型会教导编译器如何解释某个特定地址中的内存内容及其大小
      • 适用场合:从语法上看,这个操作符仅用于指针类型的转换(返回值是指针)。它用来将一个类型指针转换为另一个类型指针,它只需在编译时重新解释指针的类型。这个操作符基本不考虑转换类型之间是否是相关的。
      • 注意:在gcc上大转小不被允许,需要加编译参数:-fpermissive
      • 代码示例:
int num = 0x00636261;//用16进制表示32位int,0x61是字符'a'的ASCII码
int * pnum = &num;
char * pstr = reinterpret_cast<char *>(pnum);
cout << "pnum指针的值: " << pnum << endl;
cout << "pstr指针的值: " << static_cast<void *>(pstr) << endl;//直接输出pstr会输出其指向的字符串,这里的类型转换是为了保证输出pstr的值
// 以上两行输出的地址值是一样的
cout << "pnum指向的内容: " << hex << *pnum << endl;  // 输出636261
cout << "pstr指向的内容: " << pstr << endl;          // 输出 abc
// 如果将num的值改为64636261,patr输出abcd***(abcd后几个乱码),原因是,pstr会一直输出直到遇到'\0'
// 所以,如果访问到非法地址,会崩溃
  • dynamic_cast:支持运行时类型识别,主要被用于安全地沿着类的继承关系向下进行类型转换,将一个基类转换成派生类
    • 语法:A=dynamic_cast<typeA>(B) (typeA通常含有虚函数)
    • 该运算符把B转换成typeA类型的对象。TypeA必须是类的指针、类的引用或者void *——只能针对指针或引用进行强转;
    • dynamic_cast的转换是在运行时进行的(指向派生类的基类指针可以转成派生类类型,但静态的基类转派生类是不会成功的,同样适用于引用),它的一个好处是会在运行是做类型检查,如果对象的类型不是期望的类型,它会在指针转换的时候返回NULL,在引用转换的时候抛出一个std::bad_cast异常。所以有两个步骤:
      • 第一,判断是不是某个类型;
      • 第二,是的话就把指针强转成要的类型,不是就返回NULL或抛出异常;
    • dynamic_cast一般只在继承类对象的指针之间或引用之间进行类型转换。如果没有继承关系,则被转化的类具有虚函数对象的指针进行转换,不能被用于缺乏虚函数的类型上(more effective c++ 2)——待验证?
  • 备注:
    • 尽量避免类型转换,特别是dynamic_cast,有两种方法代替:
      • 使用容器并直接在其中存储指向derived class的指针
      • 使用虚函数代替
  • 指针类型转换:
    在这里插入图片描述

const/constexpr

const

编译期和运行时常量,两者没有区分

  • const变量:
    • const对象必须初始化,而且是在声明的时候初始化,不能分开,不然会报错。其对象一旦创建后就不能再改变,在const类型的对象上只能执行不改变其内容的操作
      • 声明时加extern,再定义(定义时可加可不加),这时候包含声明const头文件的多个文件共享同一个const对象
      • 如果声明时不加extern直接定义,包含了const变量头文件的编译单元会开辟新的内存存放该变量,类似static变量,不会报链接时重定义,但地址不同
    • 初始化对const的引用:允许为一个常量引用绑定非常量的对象,字面值(右值),甚至一般表达式,但数据类型是要一致的;常量引用仅对引用可参与的操作做出了限定,对引用的对象本身是不是常量未做限定,所以允许通过其他途径改变它的值;(常量左值引用是万能的)
      const int &r = 42; 正确;常量值(右值)作为实参传递给const T&也是允许的
    • 如果用一个对象去初始化另一个对象,则它们是不是const都无关紧要
      int i = 42; const int v = i; 可以用非const变量初始化const变量
      int j = v; 可以用const变量初始化非const变量,但注意如果变量是指针类型则不允许(常量指针还是指向常量的指针?)
    • 默认状态下const对象仅在文件内有效
    • 初始化指向常量的指针:同初始化对const的引用,允许一个指向常量的指针指向一个非常量对象;指向常量的指针要求不能通过该指针改变对象的值,但没有规定那个对象的值不能通过其他方式改变;
    • 不能用指向非常量的指针或引用指向一个常量对象,但可以用非指针或引用的const变量初始化一个非const变量
    • 顶层const(常量指针):const作用于对象本身,本身是一个常量;——*const;
    • 低层const(指针常量):所指的对象是一个常量;声明引用的const都是低层const
    • 执行拷贝操作时,顶层const不受什么影响,拷入和拷出的对象是否是常量都没什么影响;——什么意思
    • 底层const:拷入和拷出的对象必须具有相同的底层const资格,或者,两个对象的数据类型必须能够转换,一般是非常量可以转换成常量——?
  • const成员函数:
    • 默认情况下,this指针是类类型非常量版本的常量指针(如class A,默认this类型是A *const;加上const后的类型为为const A *const),这一情况使得不能在一个常量对象上调用普通的成员函数
    • 在设计类的时候,一个原则就是对于不改变数据成员的成员函数在后面加 const;不允许修改类的数据成员,但可以修改成员指针变量指向的数据;
    • 在类外定义时要加上const,在类中声明方法时可以不带const,在类外定义时可以带const——boost库中simple_segregated_storage::segregate就是这样的,感觉很奇怪
    • const对象能调用const成员函数但不能调用非const成员函数,非const对象是可以调用const成员函数的
    • const成员函数可以被具有相同形参列表的非const成员函数重载,在这种情况下,类对象的常量属性决定了调用哪个方法——已验证

constexpr

编译期常量

  • 常量表达式:值不会改变且在编译时就能得到结果的表达式
    • 一个对象是不是常量表达式由它的数据类型和初始值共同决定,数据类型是constexpr,初始值必须是常量
    • 用常量表达式初始化的const对象也是常量表达式
    • 声明constexpr类型的变量一定是一个常量且必须用常量表达式初始化
  • 常量表达式的类型要求:
    • 字面值类型:算术类型,引用,指针;string/IO/自定义等不是
    • 指针和引用的初始值受到严格限制:指针必须是nullptr或0,或存储于某个固定地址中的对象
    • 函数体内定义的变量并非存放在固定的地址中,因此不能指向这样的这样的变量;定义在所有函数体外的所有变量地址固定不变,可以用来初始化
    • 定义有效范围超出函数本身的变量,这类变量也有固定地址,可以用来初始化,如static变量?
    • constexpr定义的指针把定义的对象设置为了顶层const(仅对指针有效,对指针指向的对象无关)
    • constexpr修饰变量:const int i=1;和constexpr int j=1;两者在大多数情况下没有区别,但如果i在全局变量中编译期会为i产生数据,对于j,如果没有显式使用编译期不会为其产生数据
      const int *p = nullptr; p是一个指向整型常量的指针
      constexpr int *q = nullptr; q是一个指向整数的常量指针
  • constexpr函数:被隐式的指定为内联函数,
    • 函数的返回类型及所有形参都是字面值类型,且函数体中有且只有一条return语句(必须返回值)
    • 函数体中也可以包含其他语句,只要这些语句在运行时不执行任何操作就行(不执行任何操作有什么用?)如static_assert/using/typedef 等
    • 允许constexpr的返回值并非一个常量;所以constexpr函数不一定返回常量表达式
    • constexpr构造函数:声明了constexpr的构造函数的类就是字面值常量类了(不知道有啥用)。除了声明为=default或者=delete之外,constexpr构造函数的函数体一般为空,使用初始化列表或其他constexpr构造函数初始化成员

C++中的关键字

  • mutable:可变数据成员,在const成员函数内也能改变数据成员,通过在变量的声明中加入mutable。一个mutable数据成员永远不会是const,即使是const对象的成员
  • __declspec (novtable ):表示这个类不生成虚函数表,但继承类不受影响;使用此关键字相对节省空间——待验证
  • delctype:类型指示符,作用是选择并返回操作数的数据类型
  • register:让编译器将变量直接放入寄存器中,以提高存取速度——待验证
  • volatile:阻止编译器进行优化
    • 用法和const类似,起到对类型额外修饰的作用,只有volatile的成员函数才能被volatile的对象调用
    • 只能将volatile对象的地址赋给一个指向volatile的指针,同时只有当某个引用是volatile的时候才能使用一个volatile对象初始化该引用
    • const和volatile的一个重要区别是不能使用合成的拷贝/移动构造函数及赋值运算符初始化volatile对象或从volatile对象赋值。合成的成员接收到参数类型是非volatile,不能把一个非volatile引用绑定到一个volatile对象身上。
    • 如果一个类希望拷贝,移动或赋值它的volatile对象,则该类必须自定义拷贝或移动操作
class Foo 
{
public:
    Foo(const volatile Foo&);
    Foo& operator=(volatile const Foo&);
    Foo & operator=(volatile const Foo&) volatile;
};

union

一种节省空间的类

  • 一个union可以有多个数据成员,但在任意时刻只能有一个数据成员可以有值,当给某个成员赋值之后,该union的其他成员就变成未定义状态了。
  • 分配一个union的对象的存储空间至少要能容纳它的最大的数据成员
  • 和其他类一样,一个union定义了一种新类型
  • union不能含有引用类型的成员
  • 在C++11新标准中,含有构造和析构的类类型成员也可以作为union的成员类型,union可以为其成员指定public/protected/private等标记,默认情况下union的成员都是公有的
  • 匿名union:

基础知识点

  • 全局变量和函数:在. h中声明时加上extern,在.cpp中定义(不需要加extern);包括了声明了extern头文件的文件中可以直接使用该变量,如果没有包含头文件,需要加上extern声明
  • 不完全类型使用情景:只能是本类型的指针或引用,声明以不完全类型作为参数或返回值的函数;所以类允许包含指向自身的指针或引用
  • 单一定义规则(ODR):可以多处声明但只能单一定义;在一个头文件中不要定义,因为C++的编译单位是cpp文件,如果这个头文件被多个cpp文件包含,在.o文件链接的时候会报多处定义的错;如果非要用,可以定义成static变量;或使用extern
  • 引用和指针的区别:
    1. 引用必须要初始化,且不能为空,指针可以为空——不存在指向空值的引用意味着使用引用的代码效率比使用指针的要高,因为在使用引用前不需要测试它的合法性;相反指针应该总是被测试,防止其为空
    2. 引用类型的变量会占用内存空间,占用的内存空间的大小和指针类型的大小是相同的。
    3. 引用自始至终只能绑定一个变量,指针可以指向不同的地址
    4. sizeof 运算符应用于引用,给出它所引用的元素的大小,所以用sizoef直接计算一个引用变量的大小取到的不是引用本身的大小
  • 移位操作:
    • 左移相当于乘,左移一位乘以2
    • 右移相当于除,右移一位相当于除以2,右移两位相当于除以4
    • 对于右移大于或等于位宽的操作,或者右移负数的操作,结果依赖于编译器,不唯一,vs上为原数不变
  • C++确保delete一个空指针是安全的(vs实测delete一个NULL指针没事)
  • 数组指针和指针数组
    • 数组指针(也称行指针):是个指针,指向数组
      • 定义 int (*p)[n];
      • ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。
      • 如要将二维数组赋给一指针,应这样赋值:
        *int a[3][4];
        int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。
        p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]
        p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]
    • 指针数组:是个数组,里面包含的是指针
      • 定义 int *p[n];
      • []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1时,则p指向下一个数组元素,这样赋值是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]…p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 p=a; 这里p表示指针数组第一个元素的值,a的首地址的值。
    • 这两者的区别:数组指针似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。注意:char类型的不管是指针还是数组,都要以"\0"结尾,不然不知道何时结束,导致出现奇怪的值,或者长度和申请的长度不一致
  • strlen和sizeof的区别:
    • strlen计算长度不包含终止null字节的字符串长度,sizeof则计算了包括终止null字节的缓冲区长度
    • strlen需要一次函数调用,而对于sizeof而言,因为缓冲区已用已知字符串进行初始化,其长度是固定的,所以sizeof是在编译时计算缓冲区长度
  • 编译器会在一个字符串字面常量的末尾插入一个空字符作为终结符
const char *a = "hello";
cout << sizeof(a) << endl;    // 输出6
cout << strlen(a) << endl;    // 输出5
  • 小型对象分配:为什么需要小型对象分配器:
    • C++中的new/delete只是对C heap分配器的包装,C heap分配器并未特别对小块内存的分配进行优化,C分配器通常用来分配中大型对象(数百或数千个bytes),所以导致分配速度慢
    • C++缺省分配器的通用性也造成小型对象空间分配的低效。缺省分配器管理一个记忆池,而这种管理通常需要耗费一些额外内存,如果分配区块大的话这些开销是微不足道的,但如果分配区块小的话开销所占的比例就非常大了
    • 在C++中动态分配很重要,执行期多态和动态分配的联系最为紧密,高效的C++程序开发缺省分配器的低劣性能成为一种障碍
  • 输入/输出运算符的重载:输入输出运算符必须是非成员函数,一般声明为友元
    • 输出运算符<<:
      • 第一个形参是non-const的ostream引用,向流写入内容,所以是non-const,无法复制ostream对象,所以是引用; 第二个形参是一个常量的引用,是要打印的类类型
      • 为了与其他输出运算符保持一致,operator<<一般返回它的ostream形参
    • 输入运算符>>:
      • 第一个形参是运算符将要读取的流的引用,第二个形参是将要读到的非常量对象的引用
  • 一种for的用法:(范围for循环?)
for (int elem : coll1) {
   cout << elem << " ";
}
  • float在计算机中的存储方式:
  • 转换函数:
    • C中整数,浮点数,字符串之间的转换:
      • atoi:字符串转整数
    • C++中的转换:
      • std::stod: 字符串转浮点型
  • 数据类型的自动转换规则:
    • 若参与运算的数据类型不同,则先转成同一类型,然后进行运算——应该是先计算,再反转
    • 转换按数据长度增加的方向进行,以保证精度不降低。
    • 所有的浮点运算都是以双精度进行的,即使仅含float单精度运算的表达式
    • char和short参与运算时必须先转成int
    • 在赋值运算中赋值号两边的数据类型不同时需要把右边的类型转成左边的类型
  • 位域
    • 一个位域含有一定数量的二进制位,当一个程序需要向其他程序或者硬件设备传递二进制数据时,通常会用到位域
    • 位域在内存中的布局与机器无关
    • 位域的类型必须是整型或者枚举类型,因为带符号位域的行为是由具体实现决定的,所以在通常情况下使用无符号类型保存一个位域
    • 位域的声明形式是在名字之后紧跟一个冒号和一个常量表达式,该表达式用于指定成员所占的二进制位数
    • 取地址运算符不能用于位域,因此任何指针都无法指向类的位域
    • 通常使用内置的位运算符操作超过1位的位域
    • 如果一个类定义了位域成员,则它通常也会定义一组内联的成员函数以检验或设置位域的值:
class File
{
    unsigned int mode: 2;         // mode占2位
    unsigned int modefied: 1;
    unsigned int prot_owner: 3;
    unsigned int prot_group: 3;
    unsigned int prot_world: 3;
public:
    enum modes { READ = 01, WRITE = 02, EXECUTE = 03 };
    File &open(File::modes m) {
        mode |= READ;
        // TODO 其他处理
        if (m & WRITE) {
            return *this;
        }
    }
    inline bool isRead() const { return mode & READ; }
    inline void setWrite() { mode |= WRITE; }
};
  • 口算二进制:https://blog.csdn.net/devnn/article/details/82597660

编译与函数参数入栈总结

摘自:http://blog.csdn.net/frankiewang008/article/details/7481865

一些常见用法归纳:

  • (void)变量名:这是一些变量未曾使用,防止编译器编译时报警告或编不过的用法
  • 结构体初始化时变量名前加".":这是指定给哪个变量赋值,可以不用按顺序给结构体成员赋值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/17522.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Camtasia2023最好用的电脑屏幕录制软件

Camtasia2023是市场上最好的录像机和屏幕录制软件之一。强大的软件视频编辑程序的Camtasia 适用于Windows和iOS。 它支持多种流行的媒体格式&#xff0c;并对您创建的视频提供令人印象深刻的控制范围。3000多万专业人士在全球范围内使用Camtasia展示产品&#xff0c;教授课程&a…

文字的显示

文字的显示 文章目录 文字的显示1.文字编码方式2.英文和汉字的点阵显示3.显示中文“中”和“A”show_font.c结果 1.文字编码方式 数字>代表什么->显示为什么 GBK国标拓展 下列代码用不同编码方式保存utf-8.c ansi.c #include <stdio.h>int main(int argc ,char *…

网络编程之 Socket 套接字(使用数据报套接字和流套接字分别实现一个小程序(附源码))

文章目录 1. 什么是网络编程2. 网络编程中的基本概念1&#xff09;发送端和接收端2&#xff09;请求和响应3&#xff09;客户端和服务端4&#xff09;常见的客户端服务端模型 3. Socket 套接字1&#xff09;Socket 的分类2&#xff09;Java 数据报套接字通信模型3&#xff09;J…

基于Open3D的点云处理2-Open3D的IO与数据转换

三维数据类型 点云 某个坐标系下的点数据集&#xff0c;每个点包括三维坐标X&#xff0c;Y&#xff0c;Z、颜色、分类值、强度值、时间等信息&#xff1b; 储存格式&#xff1a;pts、LAS、PCD、xyz、asc、ply等&#xff1b;Mesh 多边形网格&#xff0c;常见的是三角网格&#…

有研究员公开了一个解析并提取 Dell PFS BIOS 固件的工具(上)

导语&#xff1a;研究员公开了一个解析并提取 Dell PFS BIOS 固件的工具。 Dell PFS BIOS提取器 介绍 解析 Dell PFS BIOS 映像并提取其 SPI/BIOS/UEFI 固件组件。它支持所有Dell PFS 修订版和格式&#xff0c;包括最初在 ThinOS 包中LZMA压缩、ZLIB压缩或拆分成块的格式。输出…

Kafka上的优化经验

1. 平滑扩容 Motivation kafka扩容⼀台新机器的流程 假如集群有 3 个 broker &#xff0c;⼀共有 4 个 TP &#xff0c;每个 3 副本&#xff0c;均匀分布。现在要扩容⼀台机器&#xff0c; 新 broker 加⼊集群后需要通过⼯具进⾏ TP 的迁移。⼀共迁移 3 个 TP 的副…

Spring Boot集成ShardingSphere实现按月数据分片及创建自定义分片算法 | Spring Cloud 44

一、前言 在前面我们通过以下章节对数据分片有了基础的了解&#xff1a; Spring Boot集成ShardingSphere实现数据分片&#xff08;一&#xff09; | Spring Cloud 40 Spring Boot集成ShardingSphere实现数据分片&#xff08;二&#xff09; | Spring Cloud 41 Spring Boot集…

权限提升:信息收集 .(Linux系统)

权限提升&#xff1a;信息收集. 权限提升简称提权&#xff0c;由于操作系统都是多用户操作系统&#xff0c;用户之间都有权限控制&#xff0c;比如通过 Web 漏洞拿到的是 Web 进程的权限&#xff0c;往往 Web 服务都是以一个权限很低的账号启动的&#xff0c;因此通过 Webshel…

1.1 基于B/S 结构的 Web 应用

文章目录 1.1 基于B/S 结构的 Web 应用1.2 JDK安装与配置1.3 服务器Tomcat下载与安装1.4 Eclipse安装与使用1.4.1 Eclipse 下载及创建Dynamic Web Project1.4.2 Eclipse 中的编码问题1.4.3 将Tomcat和Eclipse相关联1.4.4 Eclipse 自动部署项目到 Tomcat 的 webapps 目录 1.5 My…

【AWS入门】AWS Lamda

目录 创建一个Lamda函数用Lamda函数控制启停EC2实例创建一台EC2实例创建角色创建lamda函数 使用Amazon EventBridge计划启停实例创建EventBridge 用户往S3存储桶上传图片文件&#xff0c;触发Lambda函数&#xff0c;将图片压缩并上传至另一个存储桶创建两个存储桶通过Cloudform…

【SpringMVC】| SpringMVC执行流程原理 | 常用注解 剥析

MVC目录 一. &#x1f981; MVC模型二. &#x1f981; SpringMVC1. SpringMVC执行流程&#xff08;重点&#xff09;Ⅰ. SpringMVC四大组件Ⅱ. 执行流程 2. RequestMapping3. RequestParam4. ReuqestHeader & CookieValue5. RESTful风格支持Ⅰ. 传统 vs restfulⅡ. PathVar…

【网络技术】什么是CNI

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 Never look back unless you are planning to go that way. 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用…

【应急响应】日志自动提取分析项目ELKLogkitLogonTracerAnolog等

日志自动提取-七牛Logkit&观星应急工具 1、七牛Logkit&#xff1a;(Windows&Linux&Mac等) https://github.com/qiniu/logkit/ 支持的数据源&#xff08;各类日志&#xff0c;各个系统&#xff0c;各个应用等&#xff09; File: 读取文件中的日志数据&#xff0c;包…

面了一个4年经验的测试工程师,自动化都不会也要15k,我也是醉了····

在深圳这家金融公司也待了几年&#xff0c;被别人面试过也面试过别人&#xff0c;大大小小的事情也见识不少&#xff0c;今天又是团面的一天&#xff0c; 一百多个人都聚集在一起&#xff0c;因为公司最近在谈项目出来面试就2个人&#xff0c;无奈又被叫到面试房间。 整个过程…

数说热点 | 跟着《长月烬明》起飞,今年各地文旅主打的就是一个听劝

近日&#xff0c;随着热播剧《长月烬明》的爆火&#xff0c;蚌埠、宣城、敦煌等多个与剧情梦幻联动的宝藏城市被带飞&#xff0c;各地热心网友也纷纷催促自家文旅局赶紧“蹭飞”&#xff0c;《长月烬明》以一己之力打造了影视文旅融合的新样板。 仙偶剧特效天花板&#xff0c;…

《互联网安全产品漏洞管理规定》

《网络产品安全漏洞管理规定》由工业和信息化部、国家互联网信息办公室、公安部联合印发&#xff0c;自2021年9月1日起施行。 该《规定》明确&#xff0c;任何组织或者个人不得利用网络产品安全漏洞从事危害网络安全的活动&#xff0c;不得非法收集、出售、发布网络产品安全漏洞…

Redis高频面试题,使用场景

一、缓存 1、什么是缓存穿透 ? 怎么解决 ? 缓存穿透 查询一个不存在的数据&#xff0c;mysql查询不到数据也不会直接写入缓存&#xff0c;就会导致每次请求都查数据库。 解决 方案一&#xff1a;缓存空数据&#xff0c;查询返回的数据为空&#xff0c;仍把这个空结果进行…

【JavaEE】认识线程

目录 1、什么是线程 2、为什么引入线程 2.1、线程的优缺点 3、CPU的工作原理 4、线程和进程的关系 4.1、线程和进程的入口函数 4.2、线程独享的资源 1、什么是线程 一个进程中可以有一个或者多个线程&#xff0c;每个线程都是一个独立的执行流。多个线程之间&#xff0c;也…

3.rabbitMQ之发布确认高级和整合springboot(重要)找了很多博客整理出来的

1.极端情况下 rabbitMQ需要重启,导致消息投递失败(生产者发消息全部丢失)(交换机或者队列出问题) 生产者需要把数据放到缓存,用定时任务重新发送 解决方法: 0.必须配置文件写 spring.rabbitmq.publisher-confirm-typecorrelatedspring.rabbitmq.publisher-returnstruecorrelati…

Word Embedding

One-hot-encoding 缺点 1.向量维度和向量个数很大&#xff0c;假设有1w个token的话&#xff0c;向量个数和维度就都是1w 2. 语义相近的词的向量并不相似 Word Embedding 核心思想&#xff1a;可以通过上下文理解单词的语义 predection-based方法 使用前一个单词预测下一个…