C语言之声明
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语言之声明的更多相关文章
- C语言复杂声明-void (*signal(int sig, void (*handler)(int)))(int);
问题提出 请分析此声明:void (*signal(int sig, void (*handler)(int)))(int); 求解过程 在对上面的例子作分析之前,我们需要了解C语言的声明优先级,&l ...
- 《C专家编程》第三章——分析C语言的声明
前面一章我们已经说过C语言存在的一些问题和它晦涩的地方,让我们对这门神奇的语言有了更深的了解.现在这一章则集中精力来讨论C语言的声明,分为三块,首先是说明C语言声明晦涩难懂的原因和声明是如何形成的,其 ...
- C语言复杂声明
C语言复杂声明 First step int *f(); /* f:是一个函数,它返回一个指向int类型的指针*/ int (*pf)(); /* pf:是一个指向函数的指针,该函数返回一个int类型 ...
- C语言字符串声明
重新学习C语言字符串声明char *a="nihao";char a[]="nihao";什么区别?前者定义的是指针,并且指向字符串常量“nihao”,后者是字 ...
- c语言复杂声明解析
这是个好东西,接触c语言好几年了,第一次看到这东西,惊喜万分. 先提供个分析案例,以后看方便 vector <int> * (*seq_array[]) (int )={func1,fun ...
- C语言指针声明探秘
C语言指针声明探秘
- C语言变量声明内存分配
转载: C语言变量声明内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区(stack)— 程序运行时由编译器自动分配,存放函数的参数值,局部变量的值等.其操作方式类似于数据结 ...
- [日常] go语言圣经-声明,变量,赋值,类型,包和文件习题
go语言圣经-声明1.四种类型的声明语句:var.const.type和func,分别对应变量.常量.类型和函数实体对象的声明2.包一级声明语句声明的名字可在整个包对应的每个源文件中访问,局部声明的名 ...
- C语言的声明的优先级规则
C语言的声明的优先级规则如下: A 声明从它的名字开始读取,然后按照优先级顺序依次读取 B 优先级从高到低依次是: B.1 声明中被括号括起来的那一部分 B.2 后缀操作符[圆括号 ()表示这 ...
- 浅谈C语言变量声明的解析
C语言本身提供了一种不甚明确的变量声明方式——基于使用的声明,如int *a,本质上是声明了*a的类型为int,所以得到了a的类型为指向int的指针.对于简单类型,这样声明并不会对代码产生多大的阅读障 ...
随机推荐
- 关于python的GIL的解除——PEP 703 – Making the Global Interpreter Lock Optional in CPython
PEP地址: https://peps.python.org/pep-0703/ PEP 703 – Making the Global Interpreter Lock Optional in CP ...
- java多线程之自定义线程池
1.背景 线程池.....大家常用.... 自己搞一个,顺便练习一下多线程编程 2.自定义线程代码 2.1.拒绝策略接口 @FunctionalInterface public interface M ...
- 神经网络之卷积篇:详解边缘检测示例(Edge detection example)
详解边缘检测示例 卷积运算是卷积神经网络最基本的组成部分,使用边缘检测作为入门样例.在这个博客中,会看到卷积是如何进行运算的. 在之前的博客中,说过神经网络的前几层是如何检测边缘的,然后,后面的层有可 ...
- 在 React 项目中 Editable Table 的实现
我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:佳岚 可编辑表格在数栈产品中是一种比较常见的表单数据交互方 ...
- Kummer 定理
\(n!\) 中含素数 \(p\) 的幂次为 \(\displaystyle\sum_{i=1}\lfloor\frac{n}{p^{i}}\rfloor\) Kummer 定理:\({n+m\cho ...
- armbian指令大全
修复缺失内容 使用以下命令修复安装时缺失的内容: sudo apt --fix-broken install 使用 aptitude 安装软件 aptitude 是 Debian 及其衍生系统中功能强 ...
- Kubernetes利用Volume挂载ConfigMap与Secret
1.概述 在Kubernetes集群中,应用的配置管理是一个关键且复杂的任务.随着应用的扩展和微服务架构的普及,传统的配置文件管理方式已经难以满足动态.灵活的配置需求.幸运的是,Kubernetes提 ...
- manim边学边做--曲线类
manim中曲线,除了前面介绍的圆弧类曲线,也可以绘制任意的曲线. manim中提供的CubicBezier模块,可以利用三次贝塞尔曲线的方式绘制任意曲线. 关于贝塞尔曲线的介绍,可以参考:https ...
- Delta Lake 学习
解决了什么问题 delta lake 是有 ACID 支持,有time travel... 对数据可以验证,不再需要 λ 架构 对事务的ACID支持,解决了spark job 可能会中间excepti ...
- netcore高级知识点,内存对齐,原理与示例
最近几年一直从事物联网开发,与硬件打交道越来越多,发现越接近底层开发对性能的追求越高,毕竟硬件资源相对上层应用来实在是太缺乏了.今天想和大家一起分享关于C#中的内存对齐,希望通过理解和优化内存对齐,可 ...