苏州专业高端网站建设公司哪家好,湖南专业做网站公司,平面设计做兼职网站,福建建设人才市场官方网站register关键字请求“编译器”将局部变量存储于寄存器中 C语言中无法取得register变量地址
在C中依然支持register关键字 1、C编译器有自己的优化方式#xff0c;不使用register也可能做优化 2、C中可以取得register变量的地址 C编译器发现程序中需要取register变量的地址…register关键字请求“编译器”将局部变量存储于寄存器中 C语言中无法取得register变量地址
在C中依然支持register关键字 1、C编译器有自己的优化方式不使用register也可能做优化 2、C中可以取得register变量的地址 C编译器发现程序中需要取register变量的地址时register对变量的声明变得无效。
早期C语言编译器不会对代码进行优化因此register变量是一个很好的补充。 C语言的struct定义了一组变量的集合C编译器并不认为这是一种新的类型 C中的struct是一个新类型的定义声明 理论上bool只占用一个字节 如果多个bool变量定义在一起可能会各占一个bit这取决于编译器的实现 1C语言返回变量的值 C语言是返回变量本身 C语言中的三目运算符返回的是变量值不能作为左值使用 C中的三目运算符可直接返回变量本身因此可以出现在程序的任何地方
2注意三目运算符可能返回的值中如果有一个是常量值则不能作为左值使用 (a b ? 1 : b ) 30;
3C语言如何支持类似C的特性呢 当左值的条件要有内存空间C编译器帮助程序员取了一个地址而已 // C语言中 const修饰的变量是一个 常变量本质还是变量有自己的地址空间 // C中 const 变量声明的是一个真正的常量不是变量所以编译器不会为该常量分配空间 // const 修饰的常量会被放到 符号表 中 const int a 10;
// 这里对 const 常量取地址这一步操作会让编译器为该变量分配空间分配的空间并不会被 a 使用 int p (int )a;
// 通过指针改变指向的空间的值这个空间是编译器为常量分配的空间但是常量的值并不在这个空间内 // 所以即使通过指针修改了这个空间的值也不会影响到 a 本身 *p 5;
// a 的值不变因为它的值在符号表中不在程序运行的空间内 printf (“%d, %p\n”, a, *p); C中的const常量类似于宏定义 const int c 5; ≈ #define c 5 C中的const常量与宏定义不同 const常量是由编译器处理的提供类型检查和作用域检查 宏定义由预处理器处理单纯的文本替换 在程序运行过程中const变量只有一个拷贝而#define 所定义的宏变量却有多个拷贝所以宏定义在程序运行过程中所消耗的内存要比const变量的大得多 引用:
void swap1 (int a, int b)
{int tmp a;a b;b tmp;
}void swap2 (int *a, int *b)
{int tmp *a;*a *b;*b tmp;
}int main()
{int a 10;int b 20;swap2 (a, b);swap1 (a, b);printf (%d, %d\n, a, b);return 0;
}
引用在C中的内部实现是一个常指针 Type name çè Type* const name
C编译器在编译过程中使用常指针作为引用的内部实现因此引用所占用的空间大小与指针相同。
从使用的角度引用会让人误会其只是一个别名没有自己的存储空间。这是C为了实用性而做出的细节隐藏
当我们使用引用语法的时我们不去关心编译器引用是怎么做的 当我们分析奇怪的语法现象的时我们才去考虑c编译器是怎么做的 若返回栈变量 // 用非引用类型接收函数返回的引用就等于将函数返回的引用的数据值复制给了该接收对象 // 效果和返回非引用数据是一样的 若返回栈变量 不能成为其它引用的初始值 不能作为左值使用 若返回静态变量或全局变量 可以成为其他引用的初始值 即可作为右值使用也可作为左值使用 const int e 相当于 const int * const e 普通引用 相当于 int *const e1 当使用常量字面量对const引用进行初始化时C编译器会为常量值分配空间并将引用名作为这段空间的别名 使用字面量对const引用初始化后将生成一个只读变量 普通引用在定义必须要初始化引用是一块空间的别名如果空间不存在引用 就没有意义 内联函数
// 内联函数声明时inline关键字必须和函数定义结合在一起否则编译器会直接忽略内联请求。
inline int func(int a, int b)
{return a b ? a : b;
}
/*C编译器可以将一个函数进行内联编译
被C编译器内联编译的函数叫做内联函数
内联函数在最终生成的代码中是没有定义的
C编译器直接将函数体插入在函数调用的地方
内联函数没有普通函数调用时的额外开销(压栈跳转返回)
*/
//**C编译器不一定准许函数的内联请求
/*内联函数是一种特殊的函数具有普通函数的特征参数检查返回类型等
内联函数是对编译器的一种请求因此编译器可能拒绝这种请求
内联函数由 编译器处理直接将编译后的函数体插入调用的地方
宏代码片段 由预处理器处理 进行简单的文本替换没有任何编译过程
*/
/*
现代C编译器能够进行编译优化因此一些函数即使没有inline声明也可能被编译器内联编译
另外一些现代C编译器提供了扩展语法能够对函数进行强制内联
如g中的__attribute__((always_inline))属性
*/
/*
C中内联编译的限制
不能存在任何形式的循环语句
不能存在过多的条件判断语句
函数体不能过于庞大
不能对函数进行取址操作
函数内联声明必须在调用语句之前
*/
/*
编译器对于内联函数的限制并不是绝对的内联函数相对于普通函数的优势只是省去了函数调用时压栈跳转和返回的开销。因此当函数体的执行开销远大于压栈跳转和返回所用的开销时那么内联将无意义
*/ 只有参数列表后面部分的参数才可以提供默认参数值 一旦在一个函数调用中开始使用默认参数值那么这个参数后的所有参数都必须使用默 将所有同名函数作为候选者 尝试寻找可行的候选函数 1 )精确匹配实参 2) 通过默认参数能够匹配实参 3) 通过默认类型转换匹配实参 匹配失败 1) 最终寻找到的可行候选函数不唯一则出现二义性编译失败。 2) 无法匹配所有候选者函数未定义编译失败。
当使用重载函数名对函数指针进行赋值时
根据重载规则挑选与函数指针参数列表一致的候选者
严格匹配候选者的函数类型与函数指针的函数类型构造 // 一个函数返回一个对象的时候会创建一个匿名对象拿返回的那个对象 // 对匿名对象进行初始化会调用拷贝构造 // 如果没有去接收函数的返回值的话匿名对象会立马被销毁 // test6_1(); // 如果用一个对象去接收函数的返回值先用函数返回的对象去初始化 // 匿名对象调用一次拷贝构造然后拿新的对象的名字去命名这个匿名对象 // 匿名对象从无名转成有名 // Test6_1 t1 test6_1(); 当对象作为函数参数传递的时候会调用拷贝构造 析构的顺序和构造的顺序相反先构造的后析构
// 对象初始化列表,在构造函数后面加,后面加上要初始化的对象
// 对象初始化列表要比当前类的构造函数先执行
// 对象的初始化先后顺序和 在对象初始化列表 的顺序无关和在类中的声明先后顺序有关
Test9_2():m_a(10), m_c(30), m_b(20), m_ca(100)
{printf (9_2 222222222222构造函数....\n);
}
// 构造函数中调用构造函数 不会达到预期的效果的
Test10_1(int a, int b)
{m_a a;m_b b;Test10_1(a, b, 30); // 匿名对象、临时对象
}
// 静态成员函数只能使用静态成员变量
// 静态成员变量属于类不属于某个对象
// 是所有对象共享的静态是在数据区分配只有一个备份
// 静态变量不能由某个对象进行初始化
// 静态变量必须在类的外部重新定义并且初始化// 重新定义类的静态变量并且初始化
int Test11::sm_a 100; // 类的静态变量的使用
// 1、通过某一个对象进行引用
t2.sm_a 30;// 2、通过类名来引用
Test11::sm_a 60; // malloc 和 free它们本身不是C语言的语法的一部分是库函数提供的 函数 // new 和 delete: 它们本身是C语言的一部分是 运算符 不是 函数
// 创建普通类型变量
int main12_1()
{int *p1 (int *)malloc(sizeof(int));free(p1);// new 数据类型int *p2 new int;*p2 10;printf (*p2 %d\n, *p2);// 释放 new 出来的空间delete p2;// new 可以在申请空间进行初始化int *p3 new int(90);printf (*p3 %d\n, *p3);delete p3;return 0;
}// 申请数组
int main12_2()
{int *p (int *)malloc(sizeof(int) * 10);free(p);// 用 new 申请数组 new 数据类型[size]int *p1 new int[10];// deleta释放数组 必需要加 [] delete [] p1;return 0;
}class Test12
{
public:Test12(int a, int b){m_a a;m_b b;printf (构造函数\n);}~Test12(){printf (析构函数\n);}
private:int m_a;int m_b;
};// 动态创建对象
int main12_3()
{Test12 *p (Test12 *)malloc(sizeof(Test12));free(p);// new 在创建对象的时候会自动构造函数进行对象的构建Test12 *p1 new Test12(10,20);// delete在进行释放对象的时候会自动调用析构函数进行对象资源的回收delete p1;return 0;
}