因为只是一些有选择的编程技巧, 我们同样使用小点来描述
类型提升的问题
这是C中至今仍然会出现的问题,就是类型提升的问题.
起因是:优化编译器,统一类型,编译器只考虑堆栈区的变量数目,而不考虑其类型大小,
但是,计算结束后,要回到原类型, 也就是对于类型提升后的结果进行裁剪,恢复其原类型
在最早的编译器实现中,甚至只存在,int,double,指针三种类型(当然在今天看来已经是天方夜谭了)
那么,类型提升的规则如下:
对于,小于int的类型: char, short, 位段, 枚举统一提升为int(在不损失精度时),否则为unsigned int
对于float类型, 统一提升为double类型
备注: 如果运算后结果一致, 也可以省略类型提升
看个简单地例子:
#include <stdio.h>
int main(void)
{
printf("%zu\n",sizeof 'A'); #=> 4
return 0;
}
这就是类型提升的问题所在, ‘A’字符提升为int类型, 得到结果4(PS: 强制类型转换就可以发挥作用了)
函数原型与函数声明
函数声明是K&R C中的概念, 函数原型是ANSI C中的概念, 这个概念是从C++中引进的.
我们之前一直强调, 函数原型的引入是为了编译器更房变得进行类型检查
同时,它还有一个巨大的作用, 阻止类型检查, 会严格限定函数的参数接收值
int foo();
int foo()
char a, char b
// 这里如果传入的参数是char, 实际上接受到会是int(类型提升),然后函数内部裁剪为char(函数原型)
{
...
}
int func(char, char);
int func(char a, char b) // 此处严格接收char类型的参数
{
...
}
变量进行裁剪,一般情况下问题不大. 主要是溢出的处理, 但是一旦出现问题,就完蛋了
严格使用统一类型函数原型/声明
既然存在函数原型/函数声明.那么,如何选择就成为一个问题了?
要求是: 严格使用函数声明, 或者函数原型,严禁混用
我们的建议是: 统一使用函数原型
混合使用的时候, 会出现下面的问题:
原型 -> 声明
#=结果=> 期望接收类型提升后的类型,实际上接收到的是原类型, 传入short,实际一次接收两个short
声明 -> 原型
#=结果=> 传参为类型提升后的值, 是接受到原类型, int -> short, 丢失精度
单字符模式
通常情况下,我们都是通过回车来获取一个字符这里提供两种方法
1.使用stty系统调用
是我想起来了,当时暑假聊天室的字符不回显
2.使用一些系统编程函数(System Call)–ioctl
具体用法可以下来查阅,不细说,以后啃蕨菜的时候,会详尽解释(Linux/UNIX系统编程手册)
关于强制类型转换的一些事
强制类型转换实际上有什么用呢? 实际上有这样两个作用:
1> 类型转换 ,完成特定类型的需求
(int)'A'
2> 消除类型歧义, 防止不必要的类型提升
(char)'A' // 上面sizeof例子的正确改法
另外,我们再建议一种进行类型转换的方法:
要转换,你肯定是要获取类型的,对吧.所以如何获取函数类型就是个问题
去掉标识符,改为* => 去掉形式参数名 => 整体加上()
即可获取到一个函数的类型转换运算符
void func(int a, char *b);
void *ptr = func;
char ch = 'A';
(void (*)(int, char *))ptr(3, &ch); // 正确的调用方法
上面的便是本次的内容,其中有许多内容是现在可以摒弃掉的(好吧,有的也看的我云里雾里)
如有问题,可以在评论区进行讨论沟通