嵌入式八股C语言-变量与运算符篇
嵌入式八股C语言—变量与运算符篇
变量
全局变量与局部变量重名
可以的 此时全局变量就失效了
全局变量能否放在头文件中
没有问题,但不太推荐
2.1做法一:
如果是不小心重名了,但是实际上这俩变量根本没任何关系,那就用static修饰,这样变量的作用域就会限制在本文件内,此时每个.c文件的变量都独立的 没关系
2.2做法二:
只有一个头文件初始化了这个全局变量,别的头文件没初始化就行;
做法二涉及到了 符号决议 + 试探性定义 (链接的时候的事情,后面细讲)
我们在linux中运行如下代码
// a.h
// int global_K = 10;
// b.c
#include <stdio.h>
#include "a.h"
int global_k;
int main()
{
printf("%d\r\n",global_k);
}
// 打印的值是20
当然这个也看具体编译和链接的实现,作者在windows下这么干就直接报错了…
2.3做法三:
在需要用到全局变量的头文件中extern 声明
最好还是头文件声明 + 源文件定义啦
- 变量的 存储类型 作用域 生命周期 链接属性
3.1存储类型
变量的存储类型决定于我们前面的存储类关键字 不同的存储类关键字决定了变量定义在不同位置(这也是为啥这几个关键字不能一起用)
auto: 放在栈中 局部变量 随着函数调用结束就销毁了
static: 放在静态存储区: BSS段(未初始化的静态变量) / 放在数据段(初始化的静态变量)
register: 建议编译器放在寄存器中–此时不能对变量做求址运算
extern: 声明了变量的链接属性
3.2作用域
变量的有效范围
局部变量(不管static修饰不修饰)
作用域就限定在函数(或者说花括号里)死死的
int main()
{ // 直接就报错了
{
int i;
}
printf(“%d\r\n”,global_k,i);
}
全局变量
默认作用域是整个文件(a.c 定义 b.c只要extern了同名变量就能用)
也可以static修饰限制到a.c本身
3.3生命周期
变量的一生无非是: 创建->存在->销毁
全局变量生命周期:和程序一样
栈上的局部变量生命周期:随着函数调用结束结束了
堆上变量的生命周期:由程序员管理
3.4链接属性
外部链接属性 / 内部链接属性 / 无链接属性
外部链接属性: 全局变量 / 函数
内部链接属性: static 修饰的 变量/函数 只能在本文件内部
无链接属性: 局部变量不能被链接
所以存储类关键字实现上决定了变量的存储类型 / 作用域 / 生命周期
运算符
优先级
不用死记硬背 但是得知道最基本的
- 比如最高的是 () [] -> .
- & 和 * 是第二高的,不是第一高的!
分析组合起来的运算符
int (*p)(int ,int );
// 这是一个指针 名字叫p
// 往右看(是个括号) 所以这个指针指向一个函数
// 函数的返回值是int
// 传入的参数是int 类型
“=“运算符的返回值
比如 while(a = b); // 不仅把值赋给了a 还会有一个返回值
返回值是等号左边的变量的值
" ++运算符”
a++ 等价于 a = a + 1; //需要又一个temp存储临时结果
++a 是直接对a操作 不用临时变量 效果更好
不过我能想到的 一般编译器也就想到做好优化了
强制类型转换
5.1指针的强制转换
这里后面指针在细细分析 毕竟指针的 +1 太有说法了
5.2隐式类型转换–感觉和编译器有关系
规则:从低精度向高精度、从有符号数向无符号数方向转换
// 在算数运算中,所有比int小的都转换int进行计算 如果转int不够就转unsigned int计算
void compare_data1(void){
char a = -2;
unsigned char b = 3;
if( a < b) // 打印的是这个 因为是按照int去做操作的(看汇编代码)
{
printf("a < b\n");
}
else{
printf("a > b\n");
}
return;
}
void compare_data2(void){
int a = -2;
unsigned int b = 3;
if( a < b)
{
printf("a < b\n");
}
else{ // 实际打印是这个 因为都转为了无符号数
printf("a > b\n");
}
return;
}
借着博客这里的答案来说:https://www.cnblogs.com/MinPage/p/14117237.html
短路求值
对于 || 运算符 从左向右运算 只要有一个为真 后面的就不算了
对于 && 运算符 从左向右运算 只要有一个为假 后面的就不算了
左值与右值
什么是左值、右值、对象、副作用、未定义行为
- 左值:等于号左边的 一般来说值可以改变 就把左值当做 一块内存的别名 就行
- 右值:表达式 具体的值往往运行期间才可以确定
- 未定义行为: 数据访问越界 / 重复释放内存 / 直接操作未初始化的局部变量
什么是结合性、左结合、右结合?
结合性决定了当一个表达式中出现多个具有相同优先级的运算符时,这些运算符是如何组合的
左结合意味着相同优先级的运算符会从左向右计算。
右结合意味着相同优先级的运算符会从右向左计算。