网站宣传方案,网站建设维护论文,济南行业网站建设,一个地址能注册几个公司关于C语言中的Complex#xff08;复数类型#xff09;和imaginary#xff08;虚数类型#xff09; 1、C99 新增了复数类型#xff08;_Complex#xff09;和虚数类型#xff08;_Imaginary#xff09;。简单来说#xff0c;C99 提供了三种复数类型#xff1a;float _…关于C语言中的Complex复数类型和imaginary虚数类型 1、C99 新增了复数类型_Complex和虚数类型_Imaginary。简单来说C99 提供了三种复数类型float _Complexdouble _Complex和 long double _Complex。对于 float _Complex类型的变量来说它包含两个 float类型的值一个用于表示复数的实部real part另一个用于表示虚部imaginary part。类似地double _Complex 包含两个 double类型的值。C99 也提供了三种虚数类型float _Imaginarydouble _Imaginary以及 long double _Imaginary。虚数类型只有虚部没有实部。
包含标准头文件 complex.h 后我们就可以用 complex来代表 _Complex用imaginary来代表 _Imaginary以及用 I来代表虚数单位 i也就是 -1的平方根。例如
#include complex.h
double _Complex x 5.2;
double complex y 5.0 * I;
double complex z 5.2 – 5.0 * I;
注意_Complex类型对于独立式环境freestanding environment来说是可选的。可选的意思是不强制必须支持这种类型。而所谓独立式环境是指 C 程序可以在没有操作系统的情况下运行。_Imaginary类型在任何环境下都是可选的。目前的编译器对这两种类型的支持都不太好在此就不对这两种类型进行更深入的讨论了
2、C99 新增了 _Bool 类型布尔类型用于表示真/假。_Bool 类型的变量的值只能是 0 或者 1。无论赋予任何非零值给 _Bool 类型的变量它的值都只会是 1。例如 _Bool i_am_true 15; // i_am_true 的值是 1 _Bool am_i_true (var 15); // 当 var 大于 15 时am_i_true 的值为 1
包含标准头文件 stdbool.h 后我们可以用 bool 代替 _Bool true 代替 1 false 代替 0 。例如 bool no_error true; no_error false; 这么做是为了和 C 兼容stdbool.h 是 C99 新增的。
3、register修饰符 register修饰符暗示编译程序相应的变量将被频繁地使用如果可能的话应将其保存在CPU的寄存器中以加快其存储速度。例如下面的内存块拷贝代码 #ifdef NOSTRUCTASSIGN memcpy (d, s, l) {register char *d; register char *s; register int i; while (i--) *d *s; } #endif 但是使用register修饰符有几点限制。 首先register变量必须是能被CPU所接受的类型。这通常意味着register变量必须是一个单个的值并且长度应该小于或者等于整型的长度。不过有些机器的寄存器也能存放浮点数。 其次因为register变量可能不存放在内存中所以不能用“”来获取register变量的地址。 由于寄存器的数量有限而且某些寄存器只能接受特定类型的数据如指针和浮点数因此真正起作用的register修饰符的数目和类型都依赖于运行程序的机器而任何多余的register修饰符都将被编译程序所忽略。 在某些情况下把变量保存在寄存器中反而会降低程序的运行速度。因为被占用的寄存器不能再用于其它目的或者变量被使用的次数不够多不足以装入和存储变量所带来的额外开销。
4、volatile关键字
volatile总是与优化有关编译器有一种技术叫做数据流分析分析程序中的变量在哪里赋值、在哪里使用、在哪里失效分析结果可以用于常量合并常量传播等优化进一步可以死代码消除。但有时这些优化不是程序所需要的这时可以用volatile关键字禁止做这些优化volatile的字面含义是易变的它有下面的作用
1) 不会在两个操作之间把volatile变量缓存在寄存器中。在多任务、中断、甚至setjmp环境下变量可能被其他的程序改变编译器自己无法知道volatile就是告诉编译器这种情况。 2)不做常量合并、常量传播等优化所以像下面的代码 volatile int i 1; if (i 0) ... if的条件不会当作无条件真。 意思i可能被其它程序所改变
3)对volatile变量的读写不会被优化掉。如果你对一个变量赋值但后面没用到编译器常常可以省略那个赋值操作然而对Memory Mapped IO的处理是不能这样优化的。
4)volatile变量能防止优化,比如说你在某个地方可能连续调用了好几次这个函数于是编译器优化后可能就调用一次其他几次就采用这一次调用的返回值而volatile修饰后要让每一次都进行函数调用而不采用暂存值。
5、 内联函数(inline)
什么是内联函数:内联函数是为了解决C 预处理器宏存在的问题所提出一种解决方案用来提高函数使用效率。内联函数使用inline关键字定义并且函数体和申明必须结合在一起 否则编译器将他作为普通函数对待。
inline void function(int x); //仅仅是申明函数没有任何效果
inline void function(int x) //正确 { return x; }
在类内部定义的函数自动的为内联函数 不需要加关键字inline。 class point { int i; public: void SetValue(int x) //内联函数 { i x; } }
内联函数和普通函数的区别
普通函数编译器在它的符号表中放入函数类型(包含名字和参数类型的函数原型及函数的返回类型)。
内联函数函数的代码也被放入符号表代码是以源程序形式还是以编译过的汇编指令形式存放取决于编译器。 当内联函数太复杂编译器将不能执行内联。
6、restrict的含义和用法
概括的说关键字restrict只用于限定指针该关键字用于告知编译器所有修改该指针所指向内容的操作全部都是基于(base on)该指针的即不存在其它进行修改操作的途径这样的后果是帮助编译器进行更好的代码优化生成更有效率的汇编代码。举个简单的例子 int foo (int* x, int* y) ...{ *x 0; *y 1; return *x; } 很显然函数foo()的返回值是0除非参数x和y的值相同。可以想象99的情况下该函数都会返回0而不是1。然而编译起必须保证生成100%正确的代码因此编译器不能将原有代码替换成下面的更优版本
int f (int* x, int* y) ...{ *x 0; *y 1; return 0; } 现在我们有了restrict这个关键字就可以利用它来帮助编译器安全的进行代码优化了 int f (int *restrict x, int *restrict y) ...{ *x 0; *y 1; return *x; } 此时由于指针 x 是修改 *x的唯一途径编译起可以确认 “*y1; ”这行代码不会修改 *x的内容因此可以安全的优化为 int f (int *restrict x, int *restrict y) ...{ *x 0; *y 1;
return 0; } 最后注意一点restrict是C99中定义的关键字C目前并未引入在GCC可通过使用参数 -stdc99来开启对C99的支持