最近发现了一道比较有趣的题目:
void fun()
{
unsigned int a = 2013;
int b = -2;
int c = 0;
while (a + b > 0)
{
a = a + b;
c++;
}
printf("%d", c);
}
问:最后程序输出是多少?
乍一看,问题在于格式转换上,a+b 会先把b int 转成unsigned int,由于(unsigned)-2 = 0x1111 1110 也就是说a+nb不会小于0, 等于零也只有在a = 2,n = 1的情况下,于是程序会有栈溢出的问题存在。
想了想,还是总结一下格式转换的问题:
总的方向是:默认 小范围的往大范围的方式转换,比如
int+double = double, unsigned int + int = unsigned int
大的往小的,需要格式转换,一般常用格式转换是(new_type) 比如 int a = (int)0.2f
或者是指针读取:
struct IP{
byte verson_hlen;
byte service_type;
short len;
……
};
void decode(char *ipData) {
IP *p_ip = (IP*)ipData;
printf("head length: %2d, total length: %d\n",
p_ip->verson_hlen & 0x01 * 4, len);
}
其实 float => int 又与指针读取有什么区别呢? 不过是在float的地址上用int的指针读取的值(其实小数的存储方式有点特别,详情请看float的存储方式,所以这种想法还是欠妥,以及 在float与int的转换 里面你可以理解为什么判等的时候不常用小数,感兴趣的同学可以执行我下面的程序,会有意外收获,提示: 精度)
#include "stdio.h"
int main() {
if (0.6f == 0.6f)
printf("0.6f == 0.6f\n");
else
printf("0.6f != 0.6f\n");
if (0.6d == 0.6f)
printf("0.6d == 0.6f\n");
else
printf("0.6d != 0.6f\n");
if (0.5f == 0.5f)
printf("0.5f == 0.5f\n");
else
printf("0.5f != 0.5f\n");
if (0.5d == 0.5f)
printf("0.5d == 0.5f\n");
else
printf("0.5d != 0.5f\n");
return 0;
}
这里顺带提一下c++的四种类型转换:
这四种转换的用法一致:如
int a = (int)0.2f;
int a = ***_cast<int>(0.2f)
有点像函数,而里面的<int>,有点像<T>模版
类型 | 含义 |
---|---|
static_cast | 其实就是常见的类型转换,类似于 int a = (int)1.2f 在转换的过程中由于精度四舍五入,自然可能会损失数据 |
reinterpreter_cast | 是将数据重新解释,类似于上文的IP decoder,由于是只是重新解释二进制数据,所以不会造成数据的损失 |
const_cast | 将const指针(或引用)类型转换为非const指针(或引用)指针const意味着什么 |
dynamic_cast | 多态类型转换常用,具有类型检查功能,一般用于下行转换(基类转为派生类) |
上表参考
其实C++的四种类型转换是普通类型转换的俩种普例+俩种特例,附带某些功能(如去除const,类型检查)。
附:
const测试:
#include "stdio.h"
int main()
{
int num1 = 1;
const int *a = &num1;
printf("a is %d\n", *a);
num1 ++;
printf("num1++, a is %d\n", *a);
int num2 = 10;
a = &num2;
printf("a is %d\n", *a);
// int *b = a; //error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
int *b = const_cast<int*>(a);
// *a = *a + 1; //error: assignment of read-only location '* a'
// printf("a is %d\n", *a);
*b = *b + 1;
printf("b is %d\n", *b);
printf("a is %d\n", *a);
return 0;
}
/**
a is 1
num1++, a is 2
a is 10
b is 11
a is 11
**/
int main()
{
int num1 = 1;
int * const a = &num1;
printf("a is %d\n", *a);
num1 ++;
printf("num1++, a is %d\n", *a);
// int num2 = 10;
// a = &num2; //error: assignment of read-only variable 'a'
// printf("a is %d\n", *a);
int *b = a;
*a = *a + 1;
printf("a is %d\n", *a);
*b = *b + 1;
printf("b is %d\n", *b);
return 0;
}
/**
a is 1
num1++, a is 2
a is 3
b is 4
**/
const int * p | int * const p |
---|---|
p is a (pointer to)(*) const int | p is a const (pointer to)(*) int |
read-only ‘* a’(内容) | read-only ‘a’(指针) |
从上方可以看出 对于 const int *p 不能直接修改*p, 只能通过指向的num1(非const)修改 或者从const_cast得到指针cp,修改*cp。也就是*p 只读,而p可读写。(一个烂例子:你可以选择不同地方住,但是住下来了,内容是不能变动的)
对于int * const p 不能修改p的指向(*p的地址、p变量的内容),但是可以修改*p的内容,虽然不能跟换p的指向(另一个烂例子:你住的地方不好更改,但是你可以布置一下家居)