2019年11月27日

1.1、运算符优先级引发的问题

int func (int n)
{
	return n<<1+1;
}	

本意希望计算2n+1,实际运行结果是4n。因为运算符“+”优先级高于运算符“<<"。因此return (n<<1)+1;才对。
另:
y左移x位,即为y*2^(x)!!!这里左移移位即乘以2。
1.2、不加括号的宏定义引起的错误

#define PERIMETER(X,Y) 2*X+2*Y
//区别
#define PERIMETER(X,Y) (2*X+2*Y)

1.3、污染环境的宏定义
宏定义标识符重复定义了,这种情况常常能够编译通过。避免宏名称与系统库的定义同名。
1.4、多语句宏定义使用错误

#define EXIT(info) std::cerr<<info<<std::endl;exit(1)

if(data<0)
	EXIT("data is a nagative number!\n");
//展开后,
if(data<0)
	std::cerr<<info<<std::endl;
	exit(1);
//脱离本意了!!!!!		

解决方法是再加括号。也可以使用内联函数!

inline void EXIT(const char info[])
{
	std::cerr<<info<<std::endl;
	exit(1);
}
int main()
{
	int data=0;
	if(data<0)
		EXIT("data is a nagative number!");
	std::cerr<<"data is a non-negative number."<<std::endl;
}			

1.5char转换为int时高位符号扩展问题

char a=0x9A;
int util;
util=(int)a;
printf("%d",util);

实际上0x9A的二进制表示为10011010,在强制转换为int时,因为int是有符号的,需要对10011010进行符号扩展,也就是用其最高位1来扩充其他3个高字节,变成11111111 11111111 11111111 10011010(假设int是4个字节),而这个是负数-102的二进制补码表示。
正确如下:

tuil=(int)(unsigned char)a;
print("%d\n",util);

1.6int转换为char时的数据丢失
在编程过程中,对于变量的强制转换,需要注意类型的截断和扩展,特别是char、unsigned char、unsigned int、int、short等类型在赋值时的隐式转换。
1.7非法的数组下标
下表出现负值,导致程序出错。
数组下标越界,编译器是不会检查的。
1.8有符号int和无符号int比较的后果

int array[]=(23,24,12,204};
#define TOTAL_ELEMENTS (sizeof(array)/sizeof(array[0]))

sizeof()的返回值类型是无符号整型,因此代码中TOTAL_ELEMENTS的值是unsigned int类型。因此当(signed) int与unsigned int比较时,signed int会被转换为unsigned int!!!。因此即便值为-1的unsigned int,在32位操作系统上会变为2^32-1那么大!
1.10整除的精度问题

int main()
{
	float result;
	result=1/6;
	printf("result=%f\n",result);
}	

由于1和6都是整型,两个整型常量运算结果依然是整型,因此,1/6的结果为0,不会保留小数部分。

int main()
{
	float result;
	result=1.0/6;
	printf("result=%f\n",result);
}	

隐式转换:
(1)赋值时,一律右边值转化为左边类型,但是右边是表达式时,会先进行运算,然后才对运算结果进行数据类型转换。
(2)当不同类型的变量进行计算时,遵循由低优先级向高优先级转换的规则,例如char转化为整型,short转换为int,float转换为double型。
1.11浮点数比较的精度问题
在代码中,对浮点数类型进行比较不建议使用==、<=、>=、!=等比较运算符.
1.12最下负整数取相反数溢出
有符号的数据类型,均有正负数之分,如int、float、double。int表示范围不对称,例如在32位机器上,int范围为-2147483648~2147483647,如果对-2147483648取反得到的数将是溢出之后的1.所以对int类型进行取反操作时,需要额外处理这种情况。
1.13临时变量溢出

long myltiply(int m,int n)
{
	long socre;
	score=m*n;
	return score;
}	

当m、n都较大时,装满不下了。
1.15区分continue和return
用return来返回某个值并退出程序。
在for循环中,continue是结束本轮循环,执行下一次循环。

1.16指针常量和常量指针的区别

int main()
{
	int x;
	int y;
	int *const px=&x;
	

(1)可以定义const常量
const int max=100;
(2)便于进行类型检查
void f(const int I){}//对传入的参数进行类型匹配检查,不匹配进行提示。const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而后者只进行字符替换
(3)保护被修饰的东西
防止意外的修改,增强程序的健壮性。
void f(const int i)
{i=10;//error}//如果在函数体内修改了i,编译器会报错!
(4)可以方便的进行参数的调用调整和修改
同宏定义一样,可以做到不变则已,一变都变。
(5)为函数重载提供了一个参考

class A
{
	.....
	void f(int i)
	{...}//一个函数
	void f(int i) const
	{...}//上一个函数的重载
	...
}	

为纯虚函数时,取决于原型尾部那块!

class B
{
public:
	virtual int a() const=0;
	virtual void b() const=0;
	...
}			

(6)可以节省空间,避免不必要的内存分配。
const定义的常量从汇编的角度来看,只是给出对应的内存地址,而不是像宏定义一样给出立即数,const定义的常量在内存中只有一份拷贝!
(7)提高了效率
编译器通常不为普通const常量分配存储空间,而是将它们保存在符号表中,使得它成为编译期间的常量,没有了存储和读内存的操作。
(8)
1)一样的

TYPE const valueName=value;
const TYPE valueName=value;

2)沿*号画一条线
如果const位于 * 左侧,则const是用来修饰指针指向的对象
如果const位于 * 右侧,则const用来修饰指针本身
(9)
1)传递过来的参数在函数内不可以改变

void function(const int Var);

2)参数指针所指内容为常量不可变

void function(const char* Var);

3)参数指针本身为常量不可变(也无意义,因为char* Var也是形参)

void function(char* const Var);

4)参数为引用,为了增加效率同时防止修改。

void function(const Class& Var);//引用参数在函数体内不可改变
void function(const TYPE& Var);//引用参数在函数内为常量不可变
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值