C基础篇之面试笔记

1 篇文章 0 订阅

{//=================================== C 语言 ====================================

{//=======关键字  const volatile static define
	{//--static 
		{//关键字static的作用是什么?
  			这 个简单的问题很少有人能回答完全。在C语言中,关键字static有三个明显的作用: 
			1). 在函数体内,声明静态变量的函数在调用过程中值不变。
			2). 在模块内(但在函数体外),一个被声明为静态的变量可以被模块内所用函数访问,但不能被模块外其它函数访问。它是一个本地的全局变量。 
			3). 在模块内,一个被声明为静态的函数只可被这一模块内的其它函数调用。那就是,这个函数被限制在声明它的模块的本地范围内使用。 
		
	  }
		{//static全局变量与普通的全局变量有什么区别?static局部变量和普通局部变量有什么区别?static函数与普通函数有什么区别?
	  //static全局变量与普通的全局变量有什么区别:
				static全局变量只初使化一次,防止在其他文件单元中被引用;(全局变量改变为静态变量后是改变了它的作用域, 限制了它的使用范围)
	  //static局部变量和普通局部变量有什么区别:
				static局部变量只被初始化一次,下一次依据上一次结果值;(局部变量改变为静态变量后是改变了它的存储方式即改变了它的生存期。)
	  //static函数与普通函数有什么区别:
				static函数在内存中只有一份,普通函数在每个被调用中维持一份的,但指针可以
		int * const a;  //a是一个指向整型数的常指针 (也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)
		int const * a const;  //a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)

		为何用const:
		1). 关键字const的作用,告诉别人是只读的常量。
		2). 通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。 
		3). 合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。
	  -----------------------
	   int a=248; b=4;

int const c=21;
  const int *d=&a;
  int *const e=&b;
  int const *f const =&a;

请问下列表达式哪些会被编译器禁止?为什么?
  *c=32;d=&b;*d=43;e=34;e=&a;f=0x321f;

答案:
*c 这是个什么,禁止
  *d 说了是const, 禁止
  e = &a 说了是const 禁止
  const *f const =&a; 禁止
}

{//--Volatile
    {// 谈谈你对Volatile 的理解
    	
    	总结:声明为易变的,防止编译器进行优化,因为硬件经常会自动刷新寄存器
    	
    		一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。精确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 
		1). 并行设备的硬件寄存器(如:状态寄存器) 
		2). 一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 
		3). 多线程应用中被几个任务共享的变量 
					多线程访问volatile不会发生阻塞
	  }
		
		假设被面试者正确地回答了这是问题(嗯,怀疑这否会是这样),我将稍微深究一下,看一下这家伙是不是直正懂得volatile完全的重要性。 
		1). 一个参数既可以是const还可以是volatile吗?解释为什么。 
		2). 一个指针可以是volatile 吗?解释为什么。 
		3). 下面的函数有什么错误: 
		int square(volatile int *ptr) 
			{ 
			    return *ptr * *ptr; 
			} 
		
		{//下面是答案: 
			1). 是的。一个例子是只读的状态寄存器。它是volatile因为它可能被意想不到地改变。它是const因为程序不应该试图去修改它。 
			2). 是的。尽管这并不很常见。一个例子是当一个中服务子程序修该一个指向一个buffer的指针时。 
			3). 这段代码的有个恶作剧。这段代码的目的是用来返指针*ptr指向值的平方,但是,由于*ptr指向一个volatile型参数,编译器将产生类似下面的代码: 
			int square(volatile int *ptr) 
			{ 
				int a,b; 
				a = *ptr; 
				b = *ptr; 
				return a * b; 
					} 
			由于*ptr的值可能被意想不到地该变,因此a和b可能是不同的。结果,这段代码可能返不是你所期望的平方值!正确的代码如下: 
			long square(volatile int *ptr) 
			{ 
				int a; 
				a = *ptr; 
				return a * a; 
			}
	  }
}	

	{//--define
		{//用预处理指令#define 声明一个常数,用以表明1年中有多少秒(忽略闰年问题)
			#define SECONDS_PER_YEAR   (60 * 60 * 24 * 365)UL 
			我在这想看到几件事情: 
			1). #define 语法的基本知识			
		(例如:不能以分号结束,括号的使用,等等) 
			2). 懂得预处理器将为你计算常数表达式的值,因此,直接写出你是如何计算一年中有多少秒而不是计算出实际的值,是更清晰而没有代价的。 
			3). 意识到这个表达式将使一个16位机的整型数溢出-因此要用到长整型符号L,告诉编译器这个常数是的长整型数。 
			4). 如果你在你的表达式中用到UL(表示无符号长整型),那么你有了一个好的起点。记住,第一印象很重要
		}
				
		{// 写一个“标准”宏,这个宏输入两个参数并返回较小的一个。 

. #define Min(X, Y) ((X)>(Y)?(Y):(X)) //宏中小心地把参数用括号括起来
}

		{//不用中间变量,实现两变量的交换
			#define swap(x,y) \	
		x=x+y;\
								y=x-y;\
								x=x-y    //注意:结尾没有分号
		}	
						
		{//const与#define 相比,有何优点?
		    const 常量有数据类型,而宏常量没有数据类型。
		    编译器可以对前者进行类型安全检查。
		    而对后者只进行字符替换,
		    没有类型安全检查,并且在字符替换可能会产生意料不到的错误。
      有些集成化的调试工具可以对const 常量进行调试,但是不能对宏常量进行调试					
		}		
		
		{// inline(内联) 和define 对比 	
		inline代码放入预编译器符号表中,高效;它是个真正的函数,调用时有严格的参数检测
		
			//内联函数inline
			{
					是提高效率的一种方法,
					即在编译器是将所调用的函数的代码直接嵌入到主调函数中。嵌入到主调函数中的函数称内联函数。
					
					使用内联函数注意:
						1. 内联函数可以提高运行速度,但是会增加代码的长度
						2. 因为多个文件时分开编译的,所以需要把内联函数的声明以及定义放在头文件中
						3. 需要频繁使用的函数才能使用内联函数
			}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值