C语言之声明

1.声明与定义

声明语法

说明符(说明类型或修改缺省属性) 声明表达式列表

  • 说明符

    • 类型说明:int, float
    • 存储属性:static,auto
    • 类型限定:const, volatile

声明 VS 定义

  • 说明类型:取值范围和合法操作
  • 定义:分配存储空间

2.初始化

显式初始化

  • 静态变量(含全局变量):使用常量表达式初始化一次
  • 自动变量:每次执行时使用赋值语句初始化

非显式初始化

  • 静态变量(含全局变量):编译时初始化,缺省值为0
  • 自动变量:运行时初始化,缺省为无效值

3.复杂声明与typedef

复杂声明

左右法则:从最里面的圆括号(未定义的标识符)开始,先看其右边,再看其左边,遇到括号时调转方向。一旦解析完括号的内容即可跳出圆括号,重复该过程直到解析完毕。

int *(*(*f)(int))[10];
// (*f) f是一个指针
// (*f1(int)) f1是一个函数指针,所指向的函数返回值是一个指针,参数是(int)
// int *f2[10] f2是一个数组指针,指向数组 int * a[10]
// 综上,f是一个函数指针,指向函数参数为(int), 返回值为指向 int *a[10]的数组指针,其所指向的数组元素类型为 int*
// pointer to function returning pointer to array[10] of pointer to int char (*(*x())[])();
// *x(), x是一个函数,返回值类型是一个指针
// *(x1)[], x1是一个指针数组,元素类型是指针
// char x2(), x2是一个函数,返回值类型为char
// 综上,x是一个函数,返回值类型是一个指针数组,其数组元素类型是返回值类型为char的函数的指针
// function returning pointer to array[] of pointer to function returning char char (*(*x[3])())[5];
// *x[3], x是一个数组,元素类型是指针
// *x1(), x1是一个函数,返回值是指针
// char x2[5], x2是数组,元素类型是char
// 综上,x是一个数组,元素类型是函数指针,该函数返回值类型是数组指针,指向元素类型为char的数组
// array[3] of pointer to function returning pointer to array[5] of char

Unix 系统的 cdecl 程序实现了声明的解析,可参考 comp.sources.unix.newsgroup

typedef

语法和声明类似,将标识符作为类型的别名

1. 让代码更加清晰简洁

  • 定义结构体,联合,枚举等变量

    typedef struct student {
    char name[];
    int score;
    } T_Stu, *PT_Stu; T_Stu tStu1 = {"Bob", 78};
    PT_Stu ptStu1 = &tStu1; typedef enum color {
    red, white, block,
    } colot_t;
    color_t color1 = red;
  • 简化复杂声明

    // int *(*array[10])(int *p);
    typedef int *(func_ptr)(int *p);
    func_prt array[10];

2. 增加代码的可移植性

int 类型在不同的编译器和平台下所分配的存储字节不同,使用自定义的数据类型而不是内置类型来增强可移植性

#ifdef PIC_16
typedef unsigned long u32 // 2 bytes for int, 4 bytes for long
#else
typedef unsigned int u32 // 4 bytes for both int and long in PIC_32
#endif

typedef 的适用情景

  • 创建一个数据类型的别名
  • 跨平台的指定长度的类型, u32
  • 与操作系统,BSP,网络字节相关的数据类型,如size_t, pid_t等
  • 不透明的数据类型,需要隐藏数据结构实现细节,只开放函数接口

避免滥用typedef: 参考 Linux Kernel Documennt的CodingStyle

4.辨析

  • 数组与指针参数

    int fun(char *str);
    int func(char str[]);
    // 二者仅在当前声明上下文一致
  • 数组和指针初始化

    char *p = "hello";
    char a[] = "hello"; // 特殊形式,等价于 char a[] = {'h', 'e', 'l', 'l', 'o', '\0'};
  • 声明与定义

    int a;            // 变量的声明和定义
    extern int b; // 变量的声明
    void f1(void){}; // 函数的声明和定义
    void f2(void); // 函数的声明
  • typedef VS #define

    typedef等价于存储类关键字,宏定义只是字符串替换

    • typedef 不支持继续使用static等存储类关键字
    • 宏定义不支持指针声明
    • typedef 具有作用域,宏定义在预处理阶段进行全局替换
    #define int *POINTER_TO_INT
    POINTER_TO_INT a, b, c; // b, c 无法被声明为指针类型 // 与const关键字
    typedef char* PTCHAR1;
    #define PTCHAR2 char*; const PTCHAR1 p1; // PTCHAR1作为类型,可与consat调换位置,const修饰p1,指针常量
    const PTCHAR2 p2; // 等价于 const char* p2; char可与const调换位置,const修饰(*p2),常量指针

//TODO Linux 内核中的声明,学习Linux源码时

5.参考

  • 《C和指针》

    • 3.2 声明
    • 3.3 typedef
    • 13.2 高级声明
  • 《嵌入式C语言的自我修养》
    • 7.5 typedef
    • 7.8.2 复杂声明
    • 9.4 头文件的深度解析
  • 《C程序设计语言》
    • 2.4 声明
    • 4.9 初始化
    • 5.12 复杂声明
    • 6.7 类型定义(typedef)
  • 《C专家编程》
    • 3 C语言的声明
    • 4.3 声明与定义

C语言之声明的更多相关文章

  1. C语言复杂声明-void (*signal(int sig, void (*handler)(int)))(int);

    问题提出 请分析此声明:void (*signal(int sig, void (*handler)(int)))(int); 求解过程 在对上面的例子作分析之前,我们需要了解C语言的声明优先级,&l ...

  2. 《C专家编程》第三章——分析C语言的声明

    前面一章我们已经说过C语言存在的一些问题和它晦涩的地方,让我们对这门神奇的语言有了更深的了解.现在这一章则集中精力来讨论C语言的声明,分为三块,首先是说明C语言声明晦涩难懂的原因和声明是如何形成的,其 ...

  3. C语言复杂声明

    C语言复杂声明 First step int *f(); /* f:是一个函数,它返回一个指向int类型的指针*/ int (*pf)(); /* pf:是一个指向函数的指针,该函数返回一个int类型 ...

  4. C语言字符串声明

    重新学习C语言字符串声明char *a="nihao";char a[]="nihao";什么区别?前者定义的是指针,并且指向字符串常量“nihao”,后者是字 ...

  5. c语言复杂声明解析

    这是个好东西,接触c语言好几年了,第一次看到这东西,惊喜万分. 先提供个分析案例,以后看方便 vector <int> * (*seq_array[]) (int )={func1,fun ...

  6. C语言指针声明探秘

    C语言指针声明探秘

  7. C语言变量声明内存分配

    转载: C语言变量声明内存分配   一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...

  8. [日常] go语言圣经-声明,变量,赋值,类型,包和文件习题

    go语言圣经-声明1.四种类型的声明语句:var.const.type和func,分别对应变量.常量.类型和函数实体对象的声明2.包一级声明语句声明的名字可在整个包对应的每个源文件中访问,局部声明的名 ...

  9. C语言的声明的优先级规则

    C语言的声明的优先级规则如下: A 声明从它的名字开始读取,然后按照优先级顺序依次读取 B 优先级从高到低依次是:   B.1 声明中被括号括起来的那一部分   B.2 后缀操作符[圆括号 ()表示这 ...

  10. 浅谈C语言变量声明的解析

    C语言本身提供了一种不甚明确的变量声明方式——基于使用的声明,如int *a,本质上是声明了*a的类型为int,所以得到了a的类型为指向int的指针.对于简单类型,这样声明并不会对代码产生多大的阅读障 ...

随机推荐

  1. Linux下文件及文件夹权限(学习笔记版)

    本文遵循CC 4.0 BY-SA版权协议 注意:本文为学习笔记版,只记录个人觉得重要的部分,内容较为片面. Linux 下文件及文件夹的权限可以表示为rwx这三个字符,r代表read,w代表write ...

  2. tensorflow1.x——如何在C++多线程中调用同一个session会话

    相关内容: tensorflow1.x--如何在python多线程中调用同一个session会话 ================================================= 从 ...

  3. redhat8 rhel8 启动grub损坏修复

    环境:redhat8.4 RHEL8.4 服务器:华为G560 问题描述:调整了/etc/default/grub文件,重新生成/boot/grub2/grub.cfg导致机器启动失败,直接进入了re ...

  4. Windows中Powershell中的 rm -rf 等效命令

    Remove-Item  -Recurse  -Force  <要删除的目录> 可以简写为: rm -r -fo  <要删除目录>

  5. Linux CentOS 7 安装 Kafka 2.8.2 - 单机版 & JDK 11 & 切换 JDK版本

    目录 安装 JDK 11 安装 Kafka 下载 Kafka 2.8.2 防火墙 修改配置 运行测试 自启动 验证端口 Kafka 从 2.6.0 开始,默认使用 Java 11 , 3.0.0 开始 ...

  6. 我恨 gevent

    报错了一晚上,最后发现是 python 版本不对.3.11,3.12,3.8,3.10 试了个遍,最后 3.10 终于编译通过了‍ 还有这个 greenlet,每次都是它和 gevent 合着来恶心我 ...

  7. 淘宝开放平台api申请,淘宝开放平台api租用,淘宝开放平台api无法申请,淘宝开放平台api暂停接入

    目前淘宝开放平台应用申请是关闭了的,已经无法申请到了,如果你是天猫店铺,可以申请供自己店铺使用的权限,如果你不是天猫店铺或者你是软件开发商,目前是申请不到权限的 如果你必须要用到这个权限包的话,可以联 ...

  8. Python 版本管理工具选择与 Pyenv 使用说明

    Python 版本管理工具的主要作用是帮助开发者在同一台机器上管理多个 Python 版本和环境.这对于开发和部署不同项目非常有用,因为不同项目可能依赖不同的 Python 版本或者不同的包版本. 具 ...

  9. Tenzing and Random Operations CF1842G 题解

    [1] 分析 设 \(m\) 次选的位置分别为 \(b_{1\sim m}\). 于是答案为 \(\mathbb E(\prod\limits_{i = 1}^{n}(a_i + \sum\limit ...

  10. TS中的声明文件

    TS中的声明文件 .d.ts 的作用是为了在TS中使用js文件,但是js文件没有类型,ts又是一个类型严格的语言.所以为了在ts中使用js第三方包,或者自定义Js模块.便由此引出了.d.ts文件. 需 ...