编程语言的四个基本准则

    科技2024-10-07  19

    编译语言的四个基本准则

    1.最高准则---无二义性  1.1基本理解  1.2具体体现     1.2.1运算符的优先级与结合性     1.2.2 标识符命名规则     1.2.3 贪心规则     1.2.4 作用域     1.2.5 命名空间的提出     1.2.6 单定义规则 2.次高准则---高效性  2.1 基本理解  2.2 具体体现     2.2.3 数组下标为0索引     2.2.4 逻辑短路     2.2.5 C++新函数            2.2.5.1 引用            2.2.5.2 名称空间            2.2.5.3 内联函数      2.2.6 递增运算符 3.第三准则---合乎日常习惯  3.1 基本理解     3.1.1 变量,函数命名尽量有意义     3.1.2 关键字 4. 第四准则---相似相同原则  4.1 基本理解  4.2 具体体现     4.2.1变量初始化问题

    1.最高准则—无二义性

      1.1基本理解

       即一串代码只可有一种执行方式,在语义上和逻辑上不能有歧义,这同时也是所有编程语言所要遵守的最高准则。

      1.2具体体现

         1.2.1运算符的优先级与结合性

          - 优先级是为了解决语句运算中运算符使用的先后问题。      如: int i = 3 + 4 * 5; 是(3+4)×5还是3+(4×5) .

          - 结合性是为了解决当运算符优先级相同时操作数的结合性时从右向左还是从左向右的问题。      如: int j = 120 / 4 * 5; 是(120/4)×5还是120/(4×5).                      一些常见运算符优先级

    运算符结合律()从左往右+ - (一元)从右往左* /从左往右+ - (二元)从左往右=从右往左

         1.2.2 标识符命名规则

          不能用关键字当作标识符(如变量名),否则,编译器将视之为语法错误。       不可以用数字作为名称开头。因为这样将无法判断像10e3是变量名还是数字常量,违反了无二义准则;且若以数字开头,则要遍历后续字符,才可判断是否为数字常量,降低了编译的速度,也违反了高效性的原则。

          且尽量避免以下划线-开头,因为操作系统和库常使用以一个或两个下划线字符开始的标识符,进而导致名称冲突

         1.2.3 贪心规则

          每个符号应该包含尽可能多的字符,也就是说,我们的编译器将程序分解成符号的方法是从左向右一个一个字符的读入,如果该字符可以组成一个符号那么再读入下一个字符,然后在判断已经读入的两个字符是否有可能是一个符号或者一个字符的组成部分,如果可能则继续读入下一个字符,然后重复整个过程。

        如:

    int i = 10; int j = 20; int k = i+++j;

        分析得,先使用i的值后给i+1,所以i = 11; j = 20; k = (i++) + j = 10 + 20 = 30; 在分析符号时,编译器会尽可能多的结合有效的符号。

         1.2.4 作用域

           作用域是指程序中可访问标识符的区域,可分为文件作用域,块作用域,函数作用域,函数原型作用域,变量只在其对应的作用域中可见。       使用::可以访问全局变量。       内作用域同名变量定义会暂时隐藏外层变量定义。 # include <iostream> void oil(int x); int main() { using namespace std; int texas = 31; cout << "In main(), texas = " << texas << ", &texas = "; cout << &texas << endl; oil(texas); cout << "In main(), texas = " << texas << ", &texas = "; cout << &texas << endl; return 0; } void oil(int x) { using namespace std; int texas = 5; //此texas和main()中的texas不同,作用域不同,相互独立 cout << "In oil(), texas = " << texas << ", &texas = "; cout << &texas << endl; cout << "In oil(), x = " << x << ", &x = "; cout << &x << endl; { int texas = 113; //内部代码中的texas将隐藏外部代码中的Texas cout << "In block, texas = " << texas; cout << ", &texas = " << &texas << endl; } cout << "Post-block texas = " << texas; cout << ", &texas = " << &texas << endl; } /*Result: --------------------------------------------- In main(), texas = 31, &texas = 0136F970 In oil(), texas = 5, &texas = 0136F87C In oil(), x = 31, &x = 0136F890 In block, texas = 113, &texas = 0136F870 Post - block texas = 5, &texas = 0136F87C ---------------------------------------------- */

    我们看到,main()和oil()中的texas变量的内存地址都不相同

           综上,作用域使得同名变量不会发生冲突,避免了二义性。

         1.2.5 命名空间的提出

              命名空间是一种代码组织的策略,通过为变量名前加一个前缀,以便对变量进行区分,防止变量名重复。

    using namespace jack { int i = 5; ... } using namespace jill { int i = 6; ... } int main() { using namespace std; cout << " i in jack = " << jack::i << "; i in jill = " << jill::i <<endl; }

         1.2.6 单定义规则

              即变量只能有一次定义,这体现了无二义性,但这并不意味着不能有多个变量的名称相同。

    2.次高准则—高效性

      2.1 基本理解

        鉴于C++语言出现时,计算机的性能普遍较低,成为当时的一大制约因素,于是,为了解决这一问题,高效性便成为C++的次高准则。     但并非所有语言都将高效性作为次高准则,这是因为后续计算机的性能已显著提高,不再制约程序的运行速度。

      2.2 具体体现

         2.2.3 数组下标为0索引

              0索引:&a[i] = &a[0] + i * sizeof(a[0]);          1索引: &a[i] = &a[0] + (i - 1) * sizeof(a[0]);      在1索引中,需要计算(i - 1),而减法是以补码形式运行的,会导致运行速度下降。

         2.2.4 逻辑短路

          若在进行前面表达式时已经明确知道整个表达式的结果,则不会进行后面表达式的运算判断。       分为&&短路和||短路。       -||短路  如: A || B || C…|| N,若A为true,整个表达式都为true,则后续不会进行判断,若A为false,则对B进行判断,以此类推。       -&&短路  如: A&&B&&C…&&N,若A为false,则整个表达式为false,后续不再进行判断;若A为true,则判断B,以此类推。       可以将易判断的表达式写在前面有助于节省处理器的运算时间,减少代码量,提高效率。

         2.2.5 C++新函数

                2.2.5.1 引用

         可以简单理解为为变量取个别名,如 int a = 5; int &b = a; 此时,b就是a的别名。      引用的主要用途是用作形参,通过引用变量做参数,函数将使用原始数据,而不是其副本,实质上为变量提供了跨作用域调用的机制。

    引用变量和被引用变量有着相同的值和内存单元 int a = 5; int & b = a; b++; cout << "b = " << b << "; a = " << a << endl; cout << " b address =" << &b << "; a address = " << &a << endl;

    上述结果为:b = 6; a = 6; 且a和b地址相同;即b++一个操作将改变一个有两个名称的变量的值。

    用作函数参数时,可以使被调函数直接访问主调函数中的实际参量;而在传统函数值调用中,被调用函数只是使用调用程序实际参数的拷贝。 # include <iostream> void swap(int & a, int & b); int main() { using namespace std; int x = 5; int y = 8; swap(x, y); cout << "x = " << x; cout << "y = " << y; return 0; } void swap(int & a, int & b) { int t; t = a; a = b; b = t; }

    上述结果为:x = 8; y = 5;即交换a和b的值,也同时交换了主调函数中的值。

                2.2.5.2 名称空间

         见1.2.5名称空间的提出

                2.2.5.3 内联函数

         内联函数是C++为提高程序运行速度所做的一项改进。      我们知道可执行程序实质上是由机器语言指令组成,运行程序时,操作系统将这些指令载入到内存中,每一条指令都有对应的内存地址,随后,计算机将会逐步执行这些指令,当遇到函数调用语句时会立即存储调用后的内存地址,并将参数复制到堆栈,跳到标记函数起点的内存单元执行函数代码,然后跳回到地址被保存的指令处。这样来回的跳跃和记录地址意味着运行速度的降低。      因此,C++提供了内联函数。即编译器将使用相应的函数代码替换函数调用。

    inline int square(int x); inline int square(int x) { return x * x; }

         2.2.6 递增运算符

         递增运算符分为前缀模式(++i)和后缀模式(i++),让程序更加简洁的同时,也使生成的机器语言代码效率更高,因为它和实际的机器语言指令更加相似。

    3.第三准则—合乎日常习惯

      3.1 基本理解

         编程语言是由程序员使用的,目的便是方便程序员理解和书写,所以一套合乎日常习惯的规则会带来极大的方便,而一套违反日常习惯的规则,不仅会使程序员在理解和书写时造成极大的阻碍,还会使效率大大降低。

         3.1.1 变量,函数命名尽量有意义

          有意义的命名一来可以使程序更加容易理解和书写,二来方便后续程序的更改。

         3.1.2 关键字

          大部分情况下的关键字都是有意义的,在英语中有对应单词的,方便理解的。如:

    关键字意义inline内联函数float浮点类型static静态的return返回sizeof求对象byte大小

    4. 第四准则—相似相同原则

      4.1 基本理解

          C++中,如果有两个不同的对象A和B,A有行为a,B有行为b,如果a和b两种行为在逻辑上具有相似性,则C++会为对象A额外增加一个行为b,也会将对象B额外增加一个行为a。C++是在C的基础上发展得到的,所以可以从它的身上看到许多C的影子,但是C++在继承的同时又做了许多改进。

      4.2 具体体现

         4.2.1变量初始化问题

          变量有三种初始化方式:

    等号初始化:   int i = 5;

    列表初始化:    int i(5);        是变量和数组之间的“相似相同规则”。

    括号初始化:   int i{5};        是变量和对象之间的“相似相同规则”。

    Processed: 0.009, SQL: 8