再温C语言小记
2019-04-24 本文已影响0人
那个人一定不是我
char* stackValue(void){
char str[20] = {'A'};
return str;
}
void stackChange(void){
char str[20] = {'B'};
}
int main(int argc, char * argv[]) {
int result_i = 0;
unsigned long result_ul = 0;
int num_i = 0;
/*- ','逗号运算符 -*/
//赋值运算符的优先级别高于逗号运算符,逗号运算符是所有运算符中级别最低的
result_ul = 2, 3; //值为2
result_ul = (2, 3); //值为3
/*- 符号的贪婪操作,从左往右匹配到最多的符号,后置运算与编译器相关 -*/
num_i = 3;
result_ul = num_i+++num_i;
//num_i值为3; result_ul值为7 编译器相关
num_i = 3;
result_ul = (++num_i) * (++num_i) * (++num_i);
//num_i值为6; result_ul值为120 = 4*5*6
num_i = 3;
result_ul = (num_i++) * (num_i++) * (num_i++);
//num_i值为6; result_ul值为60 = 3*4*5 编译器相关
/*- 返回栈地址 危险操作-*/
char* stackRet = stackValue();
char old_c = stackRet[0]; //'A'
stackChange();
char change_c = stackRet[0]; //'B'
//数据由‘A’变为‘B’,地址对应的栈空间数据被修改
/* '*' 和 '[]'的优先级, 数组指针, 指针数组 */
int * ary[10] = {}; //'[]'的优先级高,这里是数组,存在的是‘int *’
int (*ary_p) [10] = NULL; //指针,指向储存’Int‘的数组
/* 指针加一 数组变量加一 首元素加一 */
char num_ary[5]={'A','B','C','D','E'};
//&num_ary值为数组的地址,类型为'char (*) [5]',
//加一地址为数组结束后的地址
char* c_p = (char*)(&num_ary + 1);
char c_1 = *(c_p - 1); //值为'E'
//指针类型强转为'char *',减一变为数组最后一个元素的地址
//num_ary与&num_ary[0]值相等为第一个元素地址且类型一致为’char*‘
char c_2 = *(num_ary + 1); //值为'B'
char c_3 = *(&num_ary[0] + 1); //值为'B'
/* 数组初始化指定位置 */
int new_ary[] = {
['A'] = 9,
};
//将创建储存66个Int的数组,由于‘A’的char值为65,new_ary[65] = 9;
/* sizeof 为关键字不是函数 */
int test[10];
result_ul = sizeof(test); //sizeof(int) * 100
result_ul = sizeof(test[11]);
result_ul = sizeof(&test);
result_ul = sizeof(&test[11]);
//sizeof在编译阶段进行处理获取值,运行阶段是不会执行‘test[11]’越界访问
/* const 修饰,去掉类型观看*/
int const * con_p1 = &num_i; //修饰指针对应的内容
int * const con_p2 = &num_i; //修饰指针
const int * con_p3 = &num_i; //去掉类型‘int’观看,同con_p1;
//*con_p1 = 7; //编译失败
//con_p2 = &result_i; //编译失败
/* 预处理的 #define #undef */
#define X 1
#define Y X*2
#undef X
//result_i = Y; //编译失败:‘X’未定义
/* volatile 关键字: 易失的;易变的*/
//http://www.cnblogs.com/god-of-death/p/7852394.html
/* register 关键字 */
register int num_reg = 1;
//int* num_reg_p = &num_reg; //编译错误,寄存器无法获取地址
/* enum 内存大小 */
/*enum变量占用的空间与编译器相关。
C标准:“枚举型尺寸是能够容纳最大枚举子值的整数尺寸”,
“枚举类型中枚举子的值必须要能用一个int型表述”。
也就是说,枚举型的尺寸不能超过int型,但不必等于int型,
只要能容纳最大枚举子就行。
gcc也有类似选项-fshort-enums,设置后就选用节省内存的enum长度。*/
enum Color{
Color_a = CHAR_MAX,
Color_b = CHAR_MIN,
} Color;
result_ul = sizeof(Color);
result_ul = sizeof(Color_a);
/* union 内存大小 */
/*1.联合就是一个结构;
2.它的所有成员相对于基地址的偏移量都为0;
3.此结构空间要大到足够容纳最“宽”的成员;
4.其对齐方式要适合于联合中所有类型的成员。 */
union U1{
char s[9];
char n;
};
union U2{
char s[9];
int n;
};
union U3{
char s[9];
double n;
};
result_ul = sizeof(union U1); //9
result_ul = sizeof(union U2); //12
result_ul = sizeof(union U3); //16
/* struct 内存大小 */
/*1.结构体的对齐最大单位:使用了‘pack’宏则用指定的值,
没有指定则使用结构体成员类型的最大值
(成员为数组取存储元素的类型大小用于判断,
成员为结构体取它的对齐最大单元用于判断),
2.成员的偏移量:如果其类型大小小于对齐最大单位,
那么前面占用空间必须为其类型大小的整数倍;
如果其类型大于对齐最大单位,
那么前面占用空间必须为对齐最大单位的整数倍。
(所以‘pack’宏的值只能是基础类型对应值:‘0,1,2,4,8,16’)*/
struct empty_struct {
}empty_struct;
result_ul = sizeof(empty_struct); //0
#pragma pack(2)
typedef struct{
char c1[3]; //0
char* c2; //4
}T_U1;
#pragma pack(0)
#pragma pack(4)// -> pack(1)
typedef struct{ //默认对齐大小最大值为4(i成员类型值最大4,uu为2)
char c1; //0 -> 0
short s; //2 -> 1
char c2; //4 -> 3
int i; //8 -> 4
char cc[20]; //12 -> 8
T_U1 uu; //32 -> 28
}T_Struct;
#pragma pack()
T_Struct one;
result_ul = sizeof(one); //44 -> 40
unsigned int start_addr = (unsigned int)(void*)&one;
result_ul = (unsigned int)(void*)&one.c1 - start_addr;
result_ul = (unsigned int)(void*)&one.s - start_addr;
result_ul = (unsigned int)(void*)&one.c2 - start_addr;
result_ul = (unsigned int)(void*)&one.i - start_addr;
result_ul = (unsigned int)(void*)&one.uu - start_addr;
}
Demo覆盖的内容:
- 返回栈地址
-
‘,’
号运算符 -
struct
大小 设置对齐大小 空结构图 -
enum
大小 空 有值 - 符号的贪婪操作
-
‘*’
和‘[]’
的优先级 数组指针 指正数组 - 指针加一 数组变量加一 首元素加一
- 预处理的
define undefine
-
volatile
关键字 - 数组初始化指定位置
-
sizeof
关键字不是函数 -
const
修饰 -
union
大小
看下面的Refs比上面的好看多了^_^
Refs:
《C语言深度剖析》