C_C++软件工程师就业求职手册学习笔记---第三章

第三章程序基础

3.1 变量赋值

 变量的赋值操作主要两种,一是 = ,另一种是 ++,--。对于内存操作主要是读和写。

例子1:

         x*=(y=z=3),这个语句的执行顺序是从右到左,先对z赋值,然后是y,最后在与x运算

例子2:

         主要考察作用域,对应的就是全局变量和局部变量,在局部变量作用域内,局部变量名会覆盖掉全局变量,尽量避开这种情况。

例子3:

         主要考察自增自减操作。

Printf(“%d”,n--),输出n后,n自减1

Printf(“%d”,++n),n先自增,然后在输出

Printf(“%d”,-n--),取负的运算符优先级高于右自减,所以先输出-n,然后n自减。

另外,在vc6中,printf函数输出是从右至左的操作,例如int n =5;Printf(“%d,%d”,++n,n--);输出的将是5,5;

例子4:

         对于内建数据类型,左右自增和左右自减操作的效率是一样的,才汇编语句中,可以看到,二者除了先后处理顺序不同外,没有其他差别,因此效率是一样的。

前缀式可以返回对象的引用,而后缀式则只能返回值,所以后缀存在复制开销,因此效率会变低,所以,对于非内建类型,尽量使用前缀。

3.2编程规范

1、判断等式是,尽量将定值放在左侧,变量放在右侧,例如 1==a ,避免写成a=1恒成立这样的错误。

2、在判断是否等于零时,使用范围判断,如 abs(a)<1e-6,因为对于浮点型,存在精度问题。

3、指针为空时,用NULL表示,虽然NULL定义为0,但是用NULL更直观,相比于0;

3.3 类型转换

类型不相同变量在运算时,会将低精度类型提升为高精度类型,char->unsigned char ->short->int->float ->double->long 等等,有符号的向无符号转,低的向高的转

3.4 数值交换

数值交换三种方法:

1、中间变量法,int temp =a,a=b,b=temp;

2、a=a+b;b=a-b,a=a-b;

3、a=a^b;b=a^b;a=a^b;

3.5、C与C++区别

区别:C是结构型语言,主要结构为数据结构和算法,利用算法加工数据的过程。而C++是参照现实世界,是面向对象的语言。引入对象概念,将问题抽象为对象,对象内包括数据和方法。引入了重载,继承,封装等概念。C++不仅需要考虑对象粒度,还要考虑接口的设计,以及各种特性的使用。

例子5:

C++中如何保证头文件只能被编译一次。

方法是:加入宏定义: #ifndef _MY_HEAD_H_   #define_MY_HEAD_H_  #endif 来保证。

另外,还有一种办法,就是#progma once,它是编译相关的,如果程序需要跨平台,就要用到它。

此外,在调试过程中,经常需要提示当前的一些信息,我们可以用__FILE__, __LINE__,__TIME__,__DATE__,分别来表示当前的文件名,行数,时间和日期。

例子6:

如果想要表明当前使用的编译器是C++,则应用  #ifdef __CPLUSPLUS ,如果是C编译器,则为  #ifdef __STDC__ 

要想在C++中调用C编译器,则用使用  extern “C”(具体如何使用????)

/*****************************************************************************/

    extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern "C"后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。

     这个功能十分有用处,因为在C++出现以前,很多代码都是C语言写的,而且很底层的库也是C语言写的,为了更好的支持原来的C代码和已经写好的C语言库,需要在C++中尽可能的支持C,而extern "C"就是其中的一个策略。

这个功能主要用在下面的情况:

1、C++代码调用C语言代码

2、在C++的头文件中使用

3、在多个人协同开发时,可能有的人比较擅长C语言,而有的人擅长C++,这样的情况下也会有用到

给出一个我设计的例子:

moduleA、moduleB两个模块,B调用A中的代码,其中A是用C语言实现的,而B是利用C++实现的,下面给出一种实现方法:

//moduleA头文件
#ifndef __MODULE_A_H //对于模块A来说,这个宏是为了防止头文件的重复引用
#define __MODULE_A_H
int fun(int, int);
#endif
//moduleA实现文件moduleA.C //模块A的实现部分并没有改变
#include"moduleA"
int fun(int a, int b)
{
return a+b;
}
//moduleB头文件
#idndef __MODULE_B_H //很明显这一部分也是为了防止重复引用
#define __MODULE_B_H
#ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件, extern "C"{ //因为cpp文件默认定义了该宏),则采用C语言方式进行编译
#include"moduleA.h"
#endif
… //其他代码
#ifdef __cplusplus
}
#endif
#endif
//moduleB实现文件 moduleB.cpp //B模块的实现也没有改变,只是头文件的设计变化了
#include"moduleB.h"
int main()
{
cout<<fun(2,3)<<endl;
}

下面是详细的介绍:

由于C、C++编译器对函数的编译处理是不完全相同的,尤其对于C++来说,支持函数的重载,编译后的函数一般是以函数名和形参类型来命名的。

例如函数void fun(int, int),编译后的可能是(不同编译器结果不同)_fun_int_int(不同编译器可能不同,但都采用了类似的机制,用函数名和参数类型来命名编译后的函数名);而C语言没有类似的重载机制,一般是利用函数名来指明编译后的函数名的,对应上面的函数可能会是_fun这样的名字。

看下面的一个面试题:为什么标准头文件都有类似的结构?

#ifndef __INCvxWorksh /*防止该头文件被重复引用*/
#define __INCvxWorksh
#ifdef __cplusplus            //告诉编译器,这部分代码按C语言的格式进行编译,而不是C++的
extern "C"{
#endif
/*…*/
#ifdef __cplusplus
}
#endif
#endif /*end of __INCvxWorksh*/

分析:

  • 显然,头文件中编译宏"#ifndef __INCvxWorksh 、#define __INCvxWorksh、#endif"(即上面代码中的蓝色部分)的作用是为了防止该头文件被重复引用
  • 那么

#ifdef __cplusplus (其中__cplusplus是cpp中自定义的一个宏!!!)
extern "C"{
#endif
#ifdef __cplusplus
}
#endif

的作用是什么呢?

extern "C"包含双重含义,从字面上可以知道,首先,被它修饰的目标是"extern"的;其次,被它修饰的目标代码是"C"的。

  • 被extern "C"限定的函数或变量是extern类型的

extern是C/C++语言中表明函数和全局变量的作用范围的关键字,该关键字告诉编译器,其申明的函数和变量可以在本模块或其他模块中使用。

记住,下面的语句:

extern int a; 仅仅是一个变量的声明,其并不是在定义变量a,并未为a分配空间。变量a在所有模块中作为一种全局变量只能被定义一次,否则会出错。

通常来说,在模块的头文件中对本模块提供给其他模块引用的函数和全局变量以关键字extern生命。例如,如果模块B要引用模块A中定义的全局变量和函数时只需包含模块A的头文件即可。这样模块B中调用模块A中的函数时,在编译阶段,模块B虽然找不到该函数,但并不会报错;它会在链接阶段从模块A编译生成的目标代码中找到该函数。

extern对应的关键字是static,static表明变量或者函数只能在本模块中使用,因此,被static修饰的变量或者函数不可能被extern C修饰。

  • 被extern "C"修饰的变量和函数是按照C语言方式进行编译和链接的:这点很重要!!!!

上面也提到过,由于C++支持函数重载,而C语言不支持,因此函数被C++编译后在符号库中的名字是与C语言不同的;C++编译后的函数需要加上参数的类型才能唯一标定重载后的函数,而加上extern "C"后,是为了向编译器指明这段代码按照C语言的方式进行编译

未加extern "C"声明时的链接方式:

//模块A头文件 moduleA.h
#idndef _MODULE_A_H
#define _MODULE_A_H
int foo(int x, int y);
#endif

在模块B中调用该函数:

//模块B实现文件moduleB.cpp

#include"moduleA.h"

foo(2,3);

实际上,在链接阶段,连接器会从模块A生成的目标文件moduleA.obj中找_foo_int_int这样的符号!!!,显然这是不可能找到的,因为foo()函数被编译成了_foo的符号,因此会出现链接错误。

常见的做法可以参考下面的一个实现:

moduleA、moduleB两个模块,B调用A中的代码,其中A是用C语言实现的,而B是利用C++实现的,下面给出一种实现方法:

//moduleA头文件
#ifndef __MODULE_A_H //对于模块A来说,这个宏是为了防止头文件的重复引用
#define __MODULE_A_H
int fun(int, int);
#endif
//moduleA实现文件moduleA.C //模块A的实现部分并没有改变
#include"moduleA"
int fun(int a, int b)
{
return a+b;
}
//moduleB头文件
#idndef __MODULE_B_H //很明显这一部分也是为了防止重复引用
#define __MODULE_B_H
#ifdef __cplusplus //而这一部分就是告诉编译器,如果定义了__cplusplus(即如果是cpp文件, extern "C"{ //因为cpp文件默认定义了该宏),则采用C语言方式进行编译
#include"moduleA.h"
#endif
… //其他代码
#ifdef __cplusplus
}
#endif
#endif
//moduleB实现文件 moduleB.cpp //B模块的实现也没有改变,只是头文件的设计变化了
#include"moduleB.h"
int main()
{
cout<<fun(2,3)<<endl;
}

extern "C"的使用要点

1. 可以是单一语句

   

extern "C"double sqrt(double);

2. 可以是复合语句, 相当于复合语句中的声明都加了extern "C"

   

 extern "C"
   {
      doublesqrt(double);
      int min(int,int);
  }

3.可以包含头文件,相当于头文件中的声明都加了extern"C"

  

extern "C"

  {

    #i nclude<cmath>

  }


4. 不可以将extern"C" 添加在函数内部

5. 如果函数有多个声明,可以都加extern"C", 也可以只出现在第一次声明中,后面的声明会接受第一个链接指示符的规则。

6. 除extern"C", 还有extern "FORTRAN" 等。

引用自http://blog.csdn.net/jiqiren007/article/details/5933599

/****************************************************************************/

例子6:#include <> 和“”的区别。角括号表示文件是一个工程或者标准头文件,先从预设目录开始查找,可以在环境变量中设置。而双引号则表示是用户提供的头文件,从当前目录中开始查找

3.6 main 函数之后

Main函数代表进程的主线程。程序开始执行,系统为程序创建一个进程,main函数并不是首先被调用的函数,操作系统首先调用运行期启动函数,可以对全局变量和静态变量进行创建等工作。完成这些工作后,就是调用进入点函数(控制台程序入口函数为main),在main函数里执行一些列操作后,退出main函数,启动函数调用运行期exit()函数,将返回值传给他,其中exit()会调用ExitProcess()函数结束进程。

我们可以用atexit()函数来调用main函数结束后的函数,调用顺序与注册顺序相反。

void f1()
{
         cout<<"f1"<<endl;
}
 
void f2()
{
         cout<<"f2"<<endl;
}
void main()
{
         atexit(f1);
         atexit(f2);
         cout<<"88"<<endl;
}

 

88

f2

f1

/------------------------------------------------------------第三章结束--------------------------------------------------/



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值