冷门知识
记录一下自己在学习和面试时让我头脑模糊的知识。
结构体对齐
有点无聊的知识,不过笔试常考。要想算一个结构体有多少字节数,有几个要点:
数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,每个数据成员存储的起始位置要从该成员(每个成员本身)大小的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。
结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)
收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍(结构体成员以最大成员为代表).不足的要补齐.
各个数据类型的字节数
32,64位编译环境下的 sizeof 问题经常出现。不过,两者环境下的数据类型所占字节数都是一样的,
不同的是:指针类型和 long
32位:指针类型占4个字节,long 占 4个字节。
64位:指针类型占8个字节,long 占 8个字节。
静态变量只会初始化一次
在多次调用 foo 函数时,p 只会被初始化一次,不是全局变量那样可以随意初始化。可以反向理解为 static 语句只会被执行一次,执行完之后随机删除。
C++ 命名规则
合法标识符规则如下:
由数字,字母,下划线组成;
不能由数字开头。即第一个字符只能是字母或下划线。
区分大小写。
不可与系统关键字相同。
const 限定符
_之前,则const限定的是_ptr而不限定ptr。也就是说,ptr可以改变其所指向的对象,但不能通过该指针修改其所指向对象的值。
若const限定符在_之后,则const限定的是ptr而不限定_ptr。也就是说,ptr不可以改变其所指向的对象,但能通过该指针修改其所指向对象的值。
若在_之前有const限定符且在_之后也有const限定符,则ptr与*ptr都被限定。也就是说,ptr既不可以改变其所指向的对象,也不能通过该指针修改其所指向对象的值。
另外:只要 在*之后有 const限定符,则该指针在声明时必须初始化。
fopen 那些模式
Model | Action |
---|---|
r | 以只读方式打开文件,该文件必须存在。 |
r+ | 以读/写方式打开文件,该文件必须存在。 |
rb+ | 以读/写方式打开一个二进制文件,只允许读/写数据。 |
rt+ | 以读/写方式打开一个文本文件,允许读和写。 |
w | 打开只写文件,若文件存在则长度清为 0,即该文件内容消失,若不存在则创建该文件。 |
w+ | 打开可读/写文件,若文件存在则文件长度清为零,即该文件内容会消失。若文件不存在则建立该文件。 |
a | 以附加的方式打开只写文件。若文件不存在,则会建立该文件,如果文件存在,写入的数据会被加到文件尾,即文件原先的内容会被保留(EOF 符保留)。 |
a+ | 以附加方式打开可读/写的文件。若文件不存在,则会建立该文件,如果文件存在,则写入的数据会被加到文件尾后,即文件原先的内容会被保留(原来的 EOF 符不保留)。 |
wb | 以只写方式打开或新建一个二进制文件,只允许写数据。 |
wb+ | 以读/写方式打开或建立一个二进制文件,允许读和写。 |
wt+ | 以读/写方式打开或建立一个文本文件,允许读写。 |
at+ | 以读/写方式打开一个文本文件,允许读或在文本末追加数据。 |
ab+ | 以读/写方式打开一个二进制文件,允许读或在文件末追加数据。 |
sizeof
sizeof 是 C 语言中的一个操作符 (operator), 不是函数调用 , 简单的说其作用就是返回一个对象或者类型所占的内存字节数。
对象的默认拷贝构造是浅拷贝,对于指针只会赋值,不会基于空间。
fork 和 printf 的爱恨情仇
print输出字符串如果不是一"\n"为结尾的话,就不会马上输出,而是保存在缓存区中。fork函数在创建子进程的时候会复制缓存区的数据。
ios
ios类派生istream类和ostream类,istream类和ostream类共同派生出iostream类,cin和cout都是iostream类的对象
静态链接库和动态链接库
静态链接库的优点
代码装载速度快,执行速度略比动态链接库快;
只需保证在开发者的计算机中有正确的.LIB文件,在以二进制形式发布程序时不需考虑在用户的计算机上.LIB文件是否存在及版本问题,可避免DLL地狱等问题。
动态链接库的优点
更加节省内存并减少页面交换;
DLL文件与EXE文件独立,只要输出接口不变(即名称、参数、返回值类型和调用约定不变),更换DLL文件不会对EXE文件造成任何影响,因而极大地提高了可维护性和可扩展性;
不同编程语言编写的程序只要按照函数调用约定就可以调用同一个DLL函数;
适用于大规模的软件开发,使开发过程独立、耦合度小,便于不同开发者和开发组织之间进行开发和测试。
不足之处
使用静态链接生成的可执行文件体积较大,包含相同的公共代码,造成浪费;
使用动态链接库的应用程序不是自完备的,它依赖的DLL模块也要存在,如果使用载入时动态链接,程序启动时发现DLL不存在,系统将终止程序并给出错误信息。而使用运行时动态链接,系统不会终止,但由于DLL中的导出函数不可用,程序会加载失败;速度比静态链接慢。当某个模块更新后,如果新模块与旧的模块不兼容,那么那些需要该模块才能运行的软件,统统撕掉。这在早期Windows中很常见。
格式化输出
使用操作符对数据进行格式输出时,必须包含iomanip.h头文件
基类指针指向派生类
若想调用派生类虚函数,直接调用。 若想调用基类虚函数,添加域名。
static 变量初始化(出自此处)
编译时初始化:如果静态变量本身是基本数据类型(POD),且初始化值是常量,那么这个初始化过程是在编译期间完成的。
加载时初始化:程序被加载时立即进行的初始化。这个初始化发生在main函数之前。即使程序任何地方都没访问过该变量, 仍然会进行初始化,因此形象地称之为"饿汉式初始化"。
静态变量是一个基本数据类型,但是初始值非常量
静态变量是一个类对象,这种情况下即使是使用常量初始化,也是加载时初始化,而不是编译时初始化
运行时初始化:这个初始化发生在变量第一次被引用。也就是说,从程序执行模型角度看,程序所在进程空间中,哪个线程先访问了这个变量,就是哪个线程来初始化这个变量。因此,相对于加载初始化来说,这种初始化是把真正的初始化动作推迟到第一次被访问时,因而形象地称为"懒汉式初始化"。
拷贝构造函数和赋值运算符(出自此处)
拷贝构造函数和赋值运算符的行为比较相似,都是将一个对象的值复制给另一个对象;但是其结果却有些不同,
拷贝构造函数使用传入对象的值生成一个新的对象的实例,而赋值运算符是将对象的值复制给一个已经存在的实例。
这种区别从两者的名字也可以很轻易的分辨出来,拷贝构造函数也是一种构造函数,那么它的功能就是创建一个新的对象实例;赋值运算符是执行某种运算,将一个对象的值复制给一个已经存在的实例。
调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生。如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符。
<<<<<<< HEAD
C 和 C++ 中结构体的区别
C中的结构体没有函数 但是C++的结构体可以有函数。
C++的结构体可以被类取代,因为类相对于结构体 具有封装性等优势。 C++中结构体与类的区别:
结构体中的成员访问权限不声明时候默认是 公开的;而类 是私有的
#import 和 #include 的区别
三个文件:文件A.h 文件B.h 文件C.h 文件C.h需要引入A.h、B.h ,文件B.h需要引入文件A.h,这样就重复引用了A.h两次,使用#import可以进行优化。
Objective-C 中 #import 和 #include 的区别: 预编译指令 Objective-C:#import C,C++:#include #import由gcc编译器支持 在 Objective-C 中,#import 被当成 #include 指令的改良版本来使用。除此之外,#import 确定一个文件只能被导入一次,这使你在递归包含中不会出现问题。 使用哪一个还是由你来决定。一般来说,在导入 Objective-C 头文件的时候使用 #import,包含 C 头文件时使用 #include。 #import比起#include的好处就是不会引起交叉编译
编译器自动生成的函数
空类编译器会自动生成一个默认的无参构造函数、默认的析构函数、默认的拷贝构造函数以及默认赋值函数。
最后更新于