目录
二、struct-union-enum-sizeof-typedef分析
一、const && volatile
1、const 只读变量
- const修饰的变量是只读的,本质还是变量;
- const修饰的局部变量在栈上分配空间;
- const修饰的全局变量在全局数据区分配空间;
- const只在编译期有用,在运行期无用。(const 修饰的变量不是真的常量,它只是告诉编译器该变量不能出现在赋值符号的左边。)
2、注意
- 在现代C语言编译器中,修改const全局变量将导致程序崩溃。
- 标准C语言编译器不会将const修饰的全局变量存储于只读存储区中,而是存储于可修改的全局数据区,其值依然可以改。
下面程序,在很多现代编译器中, *p = 4; 这里都会报错,而老一点的不会。
#include <stdio.h>
const int g_cc = 2;
int main()
{
const int cc = 1;
int* p = (int*)&cc;
printf("cc = %d\n", cc);
*p = 3;
printf("cc = %d\n", cc);
p = (int*)&g_cc;
printf("g_cc = %d\n", g_cc);
*p = 4;
printf("g_cc = %d\n", g_cc);
return 0;
}
3、const 本质
- C语言中的const使得变量具有只读属性。
- 现代C编译器中的const将具有全局生命周期的变量存储于只读存储区。
- const不能定义真正意义上的常量。
#include <stdio.h>
const int g_array[5] = { 0 };
void modify(int* p, int v)
{
*p = v;
}
int main()
{
int const i = 0;
const static int j = 0;
int const array[5] = { 0 };
modify((int*)&i, 1); // ok
modify((int*)&j, 2); // error 具有全局生命周期的变量存储于只读存储区
modify((int*)&array[0], 3); // ok
modify((int*)&g_array[0], 4); // error 具有全局生命周期的变量存储于只读存储区
printf("i = %d\n", i);
printf("j = %d\n", j);
printf("array[0] = %d\n", array[0]);
printf("g_array[0] = %d\n", g_array[0]);
return 0;
}
4、const修饰函数参数和返回值
- const修饰函数参数表示在函数体内不希望改变参数的值;
- const修饰函数返回值表示返回值不可改变,多用于返回指针的情形。
小贴士:
C语言中的字符串字面量存储于只读存储区中,在程序中需要使用const char*指针。
#include <stdio.h>
const char* f(const int i)
{
i = 5; // err
return "exposed Joker";
}
int main()
{
const char* pc = f(0);
printf("%s\n", pc);
pc[6] = '_'; // err
printf("%s\n", pc);
return 0;
}
5、深藏不露的volatile
- volatile可理解为“编译器警告指示字”;
- volatile告诉编译器必须每次去内存中取变量值;
- volatile主要修饰可能被多个线程访问的变量;
- volatile 也可以修饰可能被未知因数更改的变量。
6、有趣的问题
const volatile int i = 0;
一 变量i具有什么样的特性?
一 编译器如何处理这个变量?
只读变量、不可优化,每次都要去内存取值。
7、小结
- const使得变量具有只读属性
- const不能定义真正意义上的常量
- const将具有全局生命期的变量存储于只读存储区
- volatile强制编译器减少优化,必须每次从内存中取值
二、struct-union-enum-sizeof-typedef分析
1、struct 的小秘密
C语言中的struct可以看作变量的集合。
struct的问题:
一空结构体占用多大内存?
#include <stdio.h>
struct TS
{
};
int main()
{
struct TS t1;
struct TS t2;
printf("sizeof(struct TS) = %d\n", sizeof(struct TS));
printf("sizeof(t1) = %d, &t1 = %p\n", sizeof(t1), &t1);
printf("sizeof(t2) = %d, &t2 = %p\n", sizeof(t2), &t2);
return 0;
}
(1)编译器出错(BCC、VC)
(2)编译器支持(GCC)
2、结构体与柔性数组
- 柔性数组即数组大小待定的数组;
- C语言中可以由结构体产生柔性数组;
- C语言中结构体的最后一个元素可以是大小未知的数组。
上面为4个字节。
SoftArray中的array仅是一个待使用的标识符,不占用存储空间。
#include <stdio.h>
#include <malloc.h>
struct SoftArray /*定义柔性数组*/
{
int len; /*柔性数组的元素数量*/
int array[]; /*柔性数组*/
};
struct SoftArray* create_soft_array(int size) /*创建柔型数组*/
{
struct SoftArray* ret = NULL;
if (size > 0)
{
ret = (struct SoftArray*)malloc(sizeof(struct SoftArray) + sizeof(int) * size);
ret->len = size;
}
return ret;
}
void delete_soft_array(struct SoftArray* sa) /*释放柔型数组*/
{
free(sa);
}
void func(struct SoftArray* sa)/*柔型数组功能测试*/
{
int i = 0;
if (NULL != sa)
{
for (i = 0; i < sa->len; i++)
{
sa->array[i] = i + 1;
}
}
}
int main()
{
int i = 0;
struct SoftArray* sa = create_soft_array(10);
func(sa);
for (i = 0; i < sa->len; i++) /*检测测试结果*/
{
printf("%d\n", sa->array[i]);
}
delete_soft_array(sa);
return 0;
}
3、C语言中的union
- C语言中的union在语法上与struct相似
- union只分配最大成员的空间,所有成员共享这个空间
- union的使用受系统大小端的影响
小端系统:c.i的数据存在低位,当读取c.c时,由于c.c占一个字节,所以读取的是1。
大端系统:c.i的数据存在高位,当读取c.c时,由于c.c占一个字节,所以读取的是0。
所有变量共用一个内存,根据自身的内存大小,读写不同长短的内存。