C语言进阶(三):关键字和运算符(const、volatile、struct、union、enum、sizeof、typedef、注释、接续符、转义符、‘‘,““、逻辑运算符、位运算符、++--、?,

本文深入探讨了C语言中的const、volatile、struct、union、enum、sizeof、typedef等关键字和运算符的使用,包括它们的含义、应用及注意事项。还涉及了逻辑运算符、位运算符、++--、三目运算符和逗号表达式,并讨论了注释和接续符、转义符的使用规则。文章通过实例解析了这些概念,帮助读者深入理解C语言的关键特性和编程技巧。
摘要由CSDN通过智能技术生成

目录

一、const && volatile

1、const 只读变量

2、注意

3、const 本质

4、const修饰函数参数和返回值

5、深藏不露的volatile

6、有趣的问题

7、小结

二、struct-union-enum-sizeof-typedef分析

1、struct 的小秘密

2、结构体与柔性数组

3、C语言中的union

4、小结

5、枚举类型的使用方法

6、枚举类型的特殊意义

7、sizeof关键字的用法

8、sizeof是C语言的内置关键字而不是函数

9、typedef的意义

10、小结

三、注释符号

1、注释规则

2、有趣的问题

3、总结

四、接续符、转义符的使用

1、接续符的使用

2、转义符的意义

3、转义符的使用

五、单引号和双引号

1、下面的程序合法吗?

2、概念混淆

3、小结

六、逻辑运算符

1、程序中的短路

2、真假转换(!碰见0返回1,否则统统返回0)

3、小结

七、位运算符分析

1、C语言中的位运算符

2、左移和右移注意点

3、位运算与逻辑运算不同

4、小结

八、++,--操作符的本质

1、++和--操作符对应两条汇编指令

2、一对头疼的兄弟

3、面试中的奇葩(编译器:贪心法)

4、小结

九、三目运算符和逗号表达式

1、三目运算符

2、三目运算符的返回类型

3、逗号表达式

4、小结


一、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。

所有变量共用一个内存,根据自身的内存大小,读写不同长短的内存。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值