C系统级编程-复习
数组对象类型
Array of Type,它是多个相同对象类型的一维派生类型,包含两要素:元素个数,元素的对象类型
所谓多维数组,不过是元素的迭代衍生,本质还是一维的
| 声明 | 对象标识的名称 | 对象类型 | 对象存储元素类型 | 解释 |
|---|---|---|---|---|
int b[3] |
b |
int[3] |
int |
int[3]类型包含3个元素,每个元素对象类型为int |
int a[2][3] |
a |
int[2][3] |
int[3] |
int[2][3]类型包含2个元素,每个元素对象类型为int[3] |
sizeof用法
当其后跟对象类型时,必须加括号
sizeof(3); // √
sizeof 3 ; // √
sizeof(int[3]); // √
sizeof int[3] ; // ×
不完全对象类型
对象类型的其中一种分类:完全对象类型,不完全对象类型。
不完全对象类型,指缺少“能确定对象大小”信息的类型,包括:
- 缺少元素个数的数组:
extern int a[] - 变长数组VLA
- 包含不完全对象类型的struct/union
- void类型
指针对象类型
Pointer to Type,任何一种对象类型,都有对应的指针对象类型
| 原类型 | 对应指针类型 | 解释 |
|---|---|---|
int[2][3] |
int(*)[2][3] |
数组指针的语法比较怪 |
int(*)[2][3] |
int(**)[2][3] |
指针类型也是类型,也就有对应的指针类型 |
int*[2][3] |
int*(*)[2][3] |
元素为int*的[2][3]形数组,其指针类型就如第一行 |
举一反三,int(*[2])[3] 类型应该如下解构(结合上表规则):
它是一个2元素数组,数组中的元素类型是指针,该指针指向int[3](即类型为int(*)[3])
int(*ppa[2])[3]; // 此时ppa[1]没有指向具体内存,所以不能直接解引用寻找对应内存地址
int a[3] = {1,2,3};
ppa[1] = &a;
printf("%d\n", (*ppa[1])[2]); // 输出3
(*ppa[1])[2] = 10;
printf("%d\n", (*ppa[1])[2]); // 输出10
typedef使用
C提供typedef为对象类型提供别名。
对于数组、指针相关的typedef,稍显不同寻常
| 原始类型 | 目标类型(别名) | 声明语法 | 描述 |
|---|---|---|---|
int(*)[2] |
PAINT |
typedef int (*PAINT)[2]; |
倒像是声明变量了 |
int[2] |
AINT |
typedef int AINT[2]; |
|
int[2][3] |
AAINT |
typedef int AAINT[2][3]; |
由于将对象类型包装,所以指针语义将被延续:
typedef int* PINT;
int* p,q; // p是int*, q是int
PINT r,s; // r和s均为int*
内存对象的属性:值
每个内存对象的值包含两层语义:值,值的类型。可表示为二元组<Value, ValueType>
- 对于非数组对象类型:ValueType = ObjectType,对象按规则转换成Value (左值转换);
- 对于数组对象类型: Value = 第一个元素的首地址,ValueType = 元素类型对应的Pointer Type
- e.g.
int a[2],其对象类型为int[2],则a的值为<a代表的内存的首地址, int*>(可以从编译器报错中确认)
- e.g.
对内存对象的抽象:内存六元组
Object = <Addrress, ObjectType, Name, Size, Value, ValueType>
| 名称 | 含义 | 说明 |
|---|---|---|
| Address | 系统给对象分配内存的首地址编号 | 系统分配,不再改变 |
| ObjectType | 对象的类型 | 即声明变量时的变量类型 |
| Name | 对象标识符 | 即声明变量时的变量名,在符号表中,代表这块内存 |
| Size | 内存的大小 | 内存的字节数量,sizeof可得 |
| Value | 这段内存的表示值 | 根据ObjectType确定 |
| ValueType | 这段内存的表示值类型 | 根据ObjectType确定 |
内存信息读取的三步骤
定位内存 --> 识别对内存的操作类型 --> 获取相应返回值
通过表达式(左值表达式)定位内存:
- 变量名表达式
- * 和 指针 结合的表达式
对于每块内存,有3种操作类型(evaluate):
&(exp):获取exp定位的内存的首地址,返回值为<Address, ObjectType*>sizeof(exp):获取exp定位的内存的大小,返回值为<Size, size_t>exp(表达式本身):获取exp定位的内存的值,返回值为<Value, ValueType>
获取的返回值:即为值,形如<Value, ValueType>
表达式与左值
表达式:一些列操作符和操作对象组成的序列
左值:能定位到一个对象内存的表达式
表达式类型
基本表达式
后缀表达式
一元表达式
Cast表达式
条件表达式
运算表达式
位运算表达式
逻辑运算表达式
逗号运算表达式
const修饰符(qualifiers)
对于一个对象类型ObjectType,用const修饰符修饰将会产生一个新的对象类型ObjectType const(和const ObjectType等价),不过该对象的表示值类型仍为ValueType
... become qualified type, the value has unqualified version ...
| 声明 | ObjectType | ValueType | 解释 |
|---|---|---|---|
int const a = 10; |
int const |
int |
说明a表示的内存is unmodifiable |
int* const p = &a; |
int* const |
int* |
const修饰int*。p的内存表示一个int*指针,它是unmodifiable的 |
int const* p = &a; |
int const* |
int const* |
const修饰int。p的内存表示一个int const*的正常指针,其指向的内存类型是int const的,即为unmodifiable的int |
int const* const p = &a |
int const* const |
int const* |
p本身、指向的内存均为unmodifiable |
int const g[1][2] = {1,2}; |
int const[1][2] |
int const(*)[3] |
仍旧把int const当作整体看,数组的元素对象类型是int const |
对ObjectType中含有const修饰的内存的修改操作,都会导致编译错误。
const的位置摆放:若放在ObjectType之前,可能会导致歧义。例如const int* p = &a;,const究竟修饰int还是修饰int*未可知,属于未定义行为。
关于字符串
char str[8] = "hello";
双引号修饰的字符串都有一个隐藏的'\0';如上例,"hello"会在静态区找合适的空间存放'h' 'e' 'l' ... '\0',而之后可以直接通过"hello"定位到这块内存 :
- 基本的evaluate:
&"hello"获取地址,sizeof("hello")获取大小,"hello"返回值<addr, char*>(数组的表示值) sizeof("hello"),结果为6,定位到"hello"内存,返回其大小;sizeof("hello"+1-1),结果为4,"hello"作为表达式的一部分,返回值的类型是char*,+1和-1操作后整个表达式的类型仍为char*,所以为指针大小4char c = "hello"[0],c将得到'h',因为"hello"定位到内存后,后面等同数组的操作,合乎逻辑;"hello"[0] = 'e'则是一个未定义行为,视编译器而定,不要乱来char* p = "hello"; char* q = "hello";,可以想见,p和q的值应该相同,都指向同一个内存地址
在C中,有String和String Literal的区分,前者仅在结尾以'\0'结尾(如"hello world"),后者可包含多个'\0'(如"hello\0world")。不失一般性,两者可统称字符串
sizeof(String Literal):全部字符串长度,包括结尾'\0'
strlen(String Literal):第一个String的长度,不包括'\0'
sizeof("abc\0def"); // 8 : a b c \0 d e f \0
strlen("abc\0def"); // 3 : a b c
复合字面量(Compound Literal)
一种合法的后缀表达式,强调按字面意义理解Type + Initializer
int* q = (int[2]){2, 3};
同样可以定位内存,相关的evalute操作适用,且对其内存的修改为合法行为(String Literal则是未定义行为)
字面量(Literal)和常量(Constant)
| 常量 | String Literal | Compound Literal | |
|---|---|---|---|
| 是否可定位内存(为左值) | |||
| 是否能修改内存 | |||
| 值 |
C系统级编程-复习的更多相关文章
- 系统级编程(csapp)
系统级编程漫游 系统级编程提供学生从用户级.程序员的视角认识处理器.网络和操作系统,通过对汇编器和汇编代码.程序性能评测和优化.内存组织层次.网络协议和操作以及并行编程的学习,理解底层计算机系统对应用 ...
- ARMV8 datasheet学习笔记4:AArch64系统级体系结构之编程模型(1)-EL/ET/ST
1.前言 ARMV8系统级编程模型主要包括异常级别.运行状态.安全状态.同步异常.异步异常.DEBUG 本文主要对系统级编程模型做一个概要介绍 2. 异常级别 2.1 Exception level概 ...
- 转 系统级编程语言性能PK
http://www.solidot.org/story?sid=35754 看了此文,为什么我现在如此看好Rust C/C++已经统治系统编程很久,除了ObjectiveC之外语言都无法获得很高的关 ...
- [CSAPP笔记][第十章 系统级I/O]
第十章 系统级I/O 输入/输出(I/O) : 是指主存和外部设备(如磁盘,终端,网络)之间拷贝数据过程. 高级别I/O函数 scanf和printf <<和>> 使用系统级I ...
- Java-Runoob-高级编程:Java 网络编程
ylbtech-Java-Runoob-高级编程:Java 网络编程 1.返回顶部 1. Java 网络编程 网络编程是指编写运行在多个设备(计算机)的程序,这些设备都通过网络连接起来. java.n ...
- 深入理解计算机系统10——系统级I/O
系统级I/O 输入/输出 是在主存和外部设备之间拷贝数据的过程. 外部设备可以是:磁盘驱动器.终端和网络. 输入和输出都是相对于主存而言的. 输入是从I/O设备拷贝数据到主存.输出时从主存拷贝数据到I ...
- CentOS:设置系统级代理(转)
原文地址:http://www.cnblogs.com/cocowool/archive/2012/07/05/2578487.html YUM代理设置 编辑/etc/yum.conf,在最后加入 # ...
- 系统级性能分析工具perf的介绍与使用
测试环境:Ubuntu16.04(在VMWare虚拟机使用perf top存在无法显示问题) Kernel:3.13.0-32 系统级性能优化通常包括两个阶段:性能剖析(performance pro ...
- 从service弹出系统级自定义提示框,可在任意页面弹出
添加权限 <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> // 显示 ...
- 系统级IO实践学习记录
代码分析 cp1.c 功能:复制文件. #include <stdio.h>#include <stdlib.h>#include <unistd.h>#inclu ...
随机推荐
- 【Docker】安装镜像报错warning: /var/cache/yum/x86_64/7/extras/packages/epel-release-7-11.noarch.rpm: Header
这个的解决方法就是加上这个就可以了
- Qt/C++如何选择使用哪一种地图内核/不同地图的优缺点/百度高德腾讯地图/天地图/谷歌地图
一.前言说明 最近花了大半年时间,专门研究这个地图组件,几乎把各种地图的官网的手册翻了个遍,亲自写代码验证了一遍,各种API函数接口和功能全部实战一遍,然后从中提取共性,做出了基类,以及通用函数类,子 ...
- Qt开源作品32-文本框回车焦点下移
一.前言 这个demo由于太过简单,而不用过多的文字描述,其实就是实现了在一个文本框中输入完成以后,回车自动跳入下一个文本框,焦点下移,这个在很多的社保系统.医疗系统等系统中很常用,因为那些系统需要很 ...
- C#中定义类时关于CLSCompliant属性的声明
今天在做code analysis时,遇到了这个提示 Warning 1 CA1014 : Microsoft.Design : Mark 'Demo.exe' with CLSCompliant(t ...
- 解密prompt系列46. LLM结构化输出代码示例和原理分析
最近闭源大模型们都陆续支持结构化输出,这一章我们先结合demo看下开源和闭源对结构化输出的支持,随后会介绍Constrained Decoding和Format Restricting Instruc ...
- Python在多个Excel文件中找出缺失数据行数多的文件
本文介绍基于Python语言,针对一个文件夹下大量的Excel表格文件,基于其中每一个文件内.某一列数据的特征,对其加以筛选,并将符合要求与不符合要求的文件分别复制到另外两个新的文件夹中的方法. ...
- 高性能队列Disruptor
背景 Disruptor是英国外汇交易公司LMAX开发的一个高性能队列,研发的初衷是解决内存队列的延迟问题(在性能测试中发现竟然与I/O操作处于同样的数量级).基于Disruptor开发的系统单线程能 ...
- 安装WindowsXP系统
重点 1.虚拟磁盘类型必须选IDE,不然会找不到磁盘 2.下载地址:链接 ,提取码: 592u 3.可以将这个系统作成一个装机PE[大白菜] 4.安装成功后,调节分辨率时,安装VWmare Tool工 ...
- Fanatastic pg walkthrough 10 Easy
nmap 发现9090 22 和3000端口 发现漏洞 但是不知道还能读到哪些敏感文件 hacktricks 看看 https://book.hacktricks.xyz/network-servic ...
- 00-串口和SSH方式登录
登录 1.板载LED灯状态说明 USB转TTL模块准备(安装ch340驱动) a.USB转TTL模块的GND接到开发板GND b.USB转TTL模块的RX接到开发板TX c.USB转TTL模块的TX接 ...