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. 使用X11进行屏幕转播是否有价值? 最好用的远控软件是什么?

    由于有多个主机在使用,而且物理位置不在一起,所以以前往往要使用VNC软件来进行远程连接,但是其延迟比较高,使用感受不是很好,而且由于我所使用的多个主机均是Ubuntu系统,于是想到了是否可以使用X11 ...

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

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

  3. Vue Vine:带给你全新的 Vue 书写体验!

    你好,我是 Kagol,个人公众号:前端开源星球. 上个月和 TinyVue 的小伙伴们一起参加了 VueConf 24 大会,有幸认识沈青川大佬,并了解了他的 Vue Vine 项目,Vue Vin ...

  4. 给我5分钟,保证教会你在vue3中动态加载远程组件

    前言 在一些特殊的场景中(比如低代码.减少小程序包体积.类似于APP的热更新),我们需要从服务端动态加载.vue文件,然后将动态加载的远程vue组件渲染到我们的项目中.今天这篇文章我将带你学会,在vu ...

  5. 白鲸开源CEO郭炜荣获「2024中国数智化转型升级先锋人物」称号

    2024年7月24日,由数据猿主办,IDC协办,新华社中国经济信息社.上海大数据联盟.上海市数商协会.上海超级计算中心作为支持单位,举办"数智新质·力拓未来 2024企业数智化转型升级发展论 ...

  6. LeetCode216.组合总和lll

    4.组合总和lll(LeetCode216) 题目叙述: 找出所有相加之和为 n 的 k 个数的组合,且满足下列条件: 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 .该列 ...

  7. 和xshell和crt说再见,认识了一款55k star多端跨平台终端神器,强大酷炫

    一.Tabby简介 Tabby(以前称为Terminus)是一款高度可配置的终端仿真器.SSH 和串行客户端.开源且跨平台,支持在Windows.macOS和Linux系统下使用. 源码下载 http ...

  8. 不是 PHP 不行了,而是 MySQL 数据库扛不住啊

    大家好,我是码农先森. 大多数的业务场景下 PHP 还没有达到性能瓶颈,然而 MySQL 数据库就先行驾崩了.但我们总是不分青红皂白,一股脑的把原因归结于是 PHP 语言不行了,每当遇到这种情形我就会 ...

  9. Linux——添加默认路由(能ping通本网段,但是ping不通其他网段)

    2024/07/15 1.问题描述 2.问题处理 3.其他问题 1.问题描述 昨天服务器突然断电,今天重启后,网络出了些问题,具体情况如下: 能ping通本机IP ping不通网关 ping不通本网段 ...

  10. Windows 7远程桌面连接Ubuntu 18.04

    从Windows 7远程到Windows系统比较简单,只要对方电脑开启远程桌面功能就可以了,但Windows 7远程桌面连接到Ubuntu 16.04比较复杂一点,具体操作步骤如下. 1 安装xrdp ...