长期总结 - Linux性能分析命令

工具命令集合 长期总结 - Linux日志查询命令 长期总结 - Linux网络命令合集 长期总结 - Linux性能分析命令 awk常用案例 bash shell常用示例 探索kubectl - 巧用jsonpath提取有用数据 探索kubectl - kubectl诊断命令集合 perf [1] perf 是基于内核子系统的Linux的性能计数器,也被称为 perf_events,它提供了为所有事件进行性能分析的框架,perf 由两部分组成: 内核系统调用,用于提供对这些性能数据的访问 用户空间工具,用于提供收集,显示分析这些性能数据的用户空间程序 由于 perf 是内核的一部分,但要想使用 perf 还需要安装另外一部分,通常情况下安装的版本是Linux内核版本,如操作系统内核版本为 5.10 那么安装 linux-tool 后则为 5.10 bash 1 2 3 4 $ apt-get install linux-perf $ perf --version perf version 5.10.149 各系统下的包名与安装 Ubuntu/Debian: linux-perf | linux-tools ;apt-get install linux-perf CentOS/Fedora: perf ;yum install -y perf list - 列出可用事件描述符 使用 perf 子命令 list 可以列出所有的 perf 可测量事件...

debian11更新内核版本

搜索linux 内核 image bash 1 apt-cache search linux-image 然后安装对应image bash 1 sudo apt install linux-image-<flavour> 安装完成后可以看到对应的image bash 1 2 3 4 $ dpkg -l|grep linux-image ri linux-image-5.10.0-16-amd64 5.10.127-2 amd64 Linux 5.10 for 64-bit PCs (signed) ii linux-image-5.10.0-16-amd64-dbg 5.10.127-2 amd64 Debug symbols for linux-image-5.10.0-16-amd64 ii linux-image-amd64 5.10.127-2 amd64 Linux for 64-bit PCs (meta-package) 可以通过命令查看拥有的内核启动项 bash 1 grep -e "menuentry " -e submenu -e linux /boot/grub/grub.cfg 需要修改至新内核可以修改 /etc/default/grub 下的 GRUB_DEFAULT= 这里要填的值为上面命令查询出的,例如 menuentry 'Debian GNU/Linux, with Linux 5....

理解Kubernetes驱逐核心 - Pod QoS

服务质量 Quality of Service (QoS),在Kubernetes是用于解决资源抢占,延迟等方向的一种技术,是服务于调度与抢占之间的条件。 QoS 级别 QoS 与 资源限制紧密相关,正如下属展示,是一个Pod资源限制部分的配置 yaml 1 2 3 4 5 6 7 resources: limits: cpu: 200m memory: 1G requests: cpu: 500m memory: 1G 而Kubernetes 将Pod QoS 根据 CPU 与 内存的配置,将QoS分为三个等级: Guaranteed:确保的,只设置 limits 或者 requests 与 limits 为相同时则为该等级 Burstable:可突发的,只设置 requests 或 requests 低于 limits 的场景 Best-effort: 默认值,如果不设置则为这个等级 为什么要关心Pod QoS级别 在Kubernetes中,将资源分为两类:可压缩性资源 “CPU”,不可压缩性资源 “内存”。当可压缩性资源用尽时,不会被终止与驱逐,而不可压缩性资源用尽时,即Pod内存不足,此时会被OOMKiller杀掉,也就是被驱逐等操作,而了解Pod 的QoS级别可以有效避免关键Pod被驱逐。 图:Pod QoS分类 Source:https://doc.kaas.thalesdigital.io/docs/BestPractices/QOS 有上图可知,BestEffort 级别的 Pod 能够使用节点上所有资源,浙江导致其他 Pod 出现资源问题。所以这类 Pod 优先级最低,如果系统没有内存,将首先被杀死。 Pod是如何被驱逐的 当节点的计算资源不足时,kubelet 会发起驱逐,这个操作是为了避免系统OOM事件,而QoS的等级决定了驱逐的优先级,没有限制资源的 BestEffort 类型的Pod最先被驱逐,接下来资源使用率低于 Requests 的 Guaranteed 与 Burstable 将不会被其他Pod的资源使用量而驱逐,其次对于此类Pod而言,如果Pod使用了比配置(Requests)更多的资源时,会根据这两个级别Pod的优先级进行驱逐。 BestEffort 与 **Burstable **将按照先优先级,后资源使用率顺序进行驱逐...

kubernetes概念 - 理解Kubernetes的驱逐机制

驱逐 (eviction) 是指终止在Node上运行的Pod,保证workload的可用性,对于使用Kubernetes,了解驱逐机制是很有必要性的,因为通常情况下,Pod被驱逐是需要解决驱逐背后导致的问题,而想要快速定位就需要对驱逐机制进行了解。 Pod被驱逐原因 Kubernetes官方给出了下属Pod被驱逐的原因: 抢占驱逐 (Preemption and Eviction) [1] 节点压力驱逐 (Node-pressure) [2] 污点驱逐 (Taints) [3] 使用API发起驱逐 (API-initiated) [4] 排出Node上的Pod (drain) [5] 被 controller-manager 驱逐 抢占和优先级 抢占是指当节点资源不足以运行新添加的Pod时,kube-scheduler 会检查低优先级Pod而后驱逐掉这些Pod以将资源分配给优先级高的Pod。这个过程称为 “抢占” 例如这个实例是 kube-proxy 被驱逐的场景 节点压力驱逐 节点压力驱逐是指,Pod所在节点的资源,如CPU, 内存, inode等,这些资源被分为可压缩资源CPU (compressible resources) 与不可压缩资源 (incompressible resources) 磁盘IO, 内存等,当不可压缩资源不足时,Pod会被驱逐。对于此类问题的驱逐 是每个计算节点的 kubelet 通过捕获 cAdvisor 指标来监控节点的资源使用情况。 被 controller-manager 驱逐 kube-controller-manager 会定期检查节点的状态,如节点处于 NotReady 超过一定时间,或Pod部署长时间失败,这些Pod由控制平面 controller-manager 创建新的Pod已替换存在问题的Pod 通过API发起驱逐 Kubernetes为用户提供了驱逐的API,用户可以通过调用API来实现自定义的驱逐。 对于 1.22 以上版本,可以通过API policy/v1 进行驱逐 bash 1 2 3 4 5 6 7 8 9 10 11 curl -v \ -H 'Content-type: application/json' \ https://your-cluster-api-endpoint....

深入理解Kubernetes 4A - Authorization源码解析

本文是关于Kubernetes 4A解析的第2章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A Overview 在 Kubernetes 中,当一个访问请求通过了登录阶段(Authentication),必须还需要请求拥有该对象的访问权限,而授权部分也是Kubernetes API 访问控制中的第二个部分 Authorization . Authorization 在 Kubernetes中是以评估发起请求的用户,根据其身份特性评估这次请求是被 ”拒绝“ 还是 “允许”,同访问控制三部曲中其他两个插件 (Authentication, Adminssion Control) 一样,Authorization 也可以同时配置多个,当收到用户的请求时,会依次检查这个阶段配置的所有模块,如果任何一个模块对该请求授予权限(拒绝或允许),那么该阶段会直接返回,当所有模块都没有该用户所属的权限时,默认是拒绝,在Kubernetes中,被该插件拒绝的用户显示为HTTP 403。 如有错别字或理解错误地方请多多担待,代码是以1.24进行整理,实验是以1.19环境进行,差别不大 objective: 了解kubernetes Authorization机制 了解授权系统的设计 完成实验,使用 OPA 作为 Kubernetes 外部用户,权限认证模型 RBAC 的替代品 Kubernetes是如何对用户授权的 kubernetes对用户授权需要遵守的shema必须拥有下列属性,代码位于pkg\apis\authorization\types.go go 1 2 3 4 5 6 7 8 9 type SubjectAccessReview struct { // API必须实现的部分 metav1....

深入理解Kubernetes 4A - Audit源码解析

本文是关于Kubernetes 4A解析的第4章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A Overview 审计是信息系统中非常重要的一部分,Kubernetes 1.11中也增加了审计 (Auditing) 功能,通过审计功能获得 deployment, ns,等资源操作的事件。 objective: 从设计角度了解Auditing在kubernets中是如何实现的 了解kubernetes auditing webhook 完成实验,通过webhook来收集审计日志 如有错别字或理解错误地方请多多担待,代码是以1.24进行整理,实验是以1.19环境进行,差别不大。 Kubernetes Auditing 根据Kubernetes官方描述审计在kubernetes中是有控制平面 kube-apiserver 中产生的一个事件,记录了集群中所操作的资源,审计围绕下列几个维度来记录事件的: 发生了什么 发生的事件 谁触发的 发生动作的对象 在哪里检查到动作的 从哪触发的 处理行为是什么 审计生命周期开始于组件 kube-apiserver 准入控制阶段,在每个阶段内都会产生审计事件并经过预处理后写入后端,目前后端包含webhook与日志文件。 审计日志功能增加了 kube-apiserver 的内存消耗,因为会为每个请求存储了审计所需的上下文。内存的消耗取决于审计日志配置 [1]。 审计事件设计 审计的schema不同于资源API的设计,没有 metav1.ObjectMeta 属性,Event是一个事件的结构体,Policy是事件配置,属于kubernetes资源,在代码 k8s.io/apiserver/pkg/apis/audit/types.go 可以看到 go 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 type Event struct { metav1....

深入理解Kubernetes 4A - Authentication源码解析

本文是关于Kubernetes 4A解析的第1章 深入理解Kubernetes 4A - Authentication源码解析 深入理解Kubernetes 4A - Authorization源码解析 深入理解Kubernetes 4A - Admission Control源码解析 深入理解Kubernetes 4A - Audit源码解析 TLS Everywhere - 解密kubernetes集群的安全认证 所有关于Kubernetes 4A部分代码上传至仓库 github.com/cylonchau/hello-k8s-4A Overview 本章主要简单阐述kubernetes 认证相关原理,最后以实验来阐述kubernetes用户系统的思路 objective: 了解kubernetes 各种认证机制的原理 了解kubernetes 用户的概念 了解kubernetes authentication webhook 完成实验,如何将其他用户系统接入到kubernetes中的一个思路 如有错别字或理解错误地方请多多担待,代码是以1.24进行整理,实验是以1.19环境进行,差别不大。 Kubernetes 认证 在Kubernetes apiserver对于认证部分所描述的,对于所有用户访问Kubernetes API(通过任何客户端,客户端库,kubectl 等)时都会经历 验证 (Authentication) , 授权 (Authorization), 和准入控制 (Admission control) 三个阶段来完成对 “用户” 进行授权,整个流程正如下图所示 图:Kubernetes API 请求的请求处理步骤图 Source:https://www.armosec.io/blog/kubernetes-admission-controller/ 其中在大多数教程中,在对这三个阶段所做的工作大致上为: Authentication 阶段所指用于确认请求访问Kubernetes API 用户是否为合法用户,拒绝为401 Authorization 阶段所指的将是这个用户是否有对操作的资源的权限,拒绝为403 Admission control 阶段所指控制对请求资源进行控制,通俗来说,就是一票否决权,即使前两个步骤完成...

理解ldap - 使用SSSD接入OpenLDAP实现身份验证

openldap合集 ch1 理解ldap - 什么是ldap ch2 理解ldap - OpenLDAP安装 ch3 理解ldap - OpenLDAP客户端命令行使用 ch4 理解ldap - OpenLDAP架构与Schema设计 ch5 理解ldap - OpenLDAP使用SSL/TLS通信安全 ch6 理解ldap - OpenLDAP中的4种复制机制 ch7 理解ldap - OpenLDAP访问控制(ACL) ch8 理解ldap - OpenLDAP备份与恢复策略 ch9 理解ldap - openldap中的一些高级配置 ch10 理解ldap - Linux系统接入OpenLDAP做认证后端 ch11 理解ldap - 使用SSSD接入OpenLDAP实现身份验证 Overview SSSD (System Security Services Daemon) 是一套用于远程身份验证的套件服务,为使用SSSD服务的客户端提供了远程访问身份认证服务来获取权限,其后端包括AD, LDAP等,本文将围绕下列方向来阐述SSSD: 为什么需要SSSD,以及使用SSSD来解决什么 使用SSSD的好处 SSSD服务工作原理及架构 如何在Linux上配置SSSD+LDAP 为什么需要SSSD SSSD设计主要是为了传统使用身份认证服务,例如PAM+NSS架构中存在的一些问题: PAM+NSS扩展性差,并配置较为复杂,尽管提供了 authconfig ,通常在大多数教程中以及不同的系统中配置都不相同 PAM+NSS不是真正意义上的离线身份认证,如果当 nslcd 或者 slapd 等服务异常时,无法完成用户认证 以及越来越多的后端,例如LDAP, AD, IPA, IdM,Kerberos等无法做到很好的适配 SSSD就是为了解决上述的问题,对于Linux平台中,SSSD拥有比传统PAM+NSS更好的优势:...

ipset性能测试

测试方法 基于使用场景,最后⽣成的规则会是按照 ip 或者 ip:port 来进行过滤,测试时将使用10万条 iptables 规则来模拟对性能的压力;为了最大化测试压力情况,10万条 iptables 规则将都是==不会匹配==机房流量,通俗来讲,就是链式匹配会进行所有匹配并最后以无匹配告终。 网络负载的模拟将使用同机房 scp 来模拟,并按照下述条件进行匹配: 查看正常的拷贝速度,cpu负载等 我们建⽴10万条的普通 iptables 规则,查看规则建立速度,拷贝速度,CPU负载,CPU主要耗时操作等 我们建⽴10万的 ipset ,并把普通的 iptables 规则转为结合 ipset 的规则,查看规则建立速度,拷贝速度,CPU负载,CPU主要耗时等。 实验开始 步骤一:在同机房的⼀个机器构造⼀个大文件 同机房拷贝 观察网卡速度,CPU,系统主要耗时操作的等,此场景将在iptables 规则为空的情况下进行观察 使用 sar 观测网卡速度 使用 top 观察CPU负载 使用 perf top -G 观察CPU占用 步骤二:创建10万条iptables,观察⽹卡速度、cpu、系统主要耗时操作的等,会发现cpu利⽤率⼤部分被ipt占⽤,拷⻉速度下降到不到⼗分之⼀ bash 1 2 3 4 5 6 7 8 #!/bin/bash echo *filter for ((i=1;i<=$1;i++)) do echo -I INPUT -S $i -j ACCEPT done echo COMMIT 执行脚本 bash 1 $ time ....

为什么网络是分层的

Overview [1] 协议数据单元 Protocol Data Unit (PDU) 是应用于OSI模型中的数据结构,在OSI模型中每一层都会被添加一个header,tailer进行封装,header, tailer加原始报文的组合就是PDU。 在每层中,PDU的名称都是不同的,这也是很多人的疑问,一会数据报文称为数据包,一会数据报文成为数据帧,该文介绍网络中的单元,以了解之间的区别 物理层 物理层数据的呈现方式是以 “位” (bit) 为单位的,即0 1,在该层中数据以二进制形式进行传输 数据链路层 [2] 到达数据链路层,实际上可以说进入了TCP/IP栈对底层,而该层的单位为 ”帧“ (frame),该层中,MAC地址会被封装到数据包中,比如以太网帧,PPP帧都是指该层的数据包 该层中数据帧包含: 源MAC 目的MAC 数据,由网络层给出的 数据的总长度 校验序列 网络层 [3] 在网络层中协议数据单元被称为数据 “包" (package) ,是网络间节点通讯的基本单位。该层中IP地址会被封装到数据包内。 该层中数据包包含: 标头:源IP,目的IP,协议,数据包编号,帮助数据包匹配网络的位 payload:数据包的主体 标尾:包含几个位,用于告知已到达数据包的末尾与错误检查(循环冗余检查 (CRC)) 图:数据包组成 Source:https://computer.howstuffworks.com/question525.htm 例如一个电子邮件,假设电子邮件大小尾3500bit,发送时使用1024的固定大小数据包进行发送,那么每个数据包标头为 96bits,标尾为 32bit,剩余 896bits 将用于实际的数据大小。这里为3500bits,会被分为4个数据包,前三个数据包为 896bits,最后一个数据包大小为 812bits。接收端会根据包编号进行解包重组 传输层 Segment 在传输层TCP协议的协议数据单元被称为 ”段“ (Segment) ,上面讲到,IP数据包会以固定大小的数据包进行发送,如果超出大小的会被划分为多个数据包,每个数据包的碎片就被称之为Segment。 数据包分割通常会发生在该层,当发生下列场景时会需要分段 数据包大于网络支持的最大传输单元 (MTU) 网络不可靠,将数据包分为更小的包 datagram [4] 在传输层UDP协议的协议数据单元被称为 ”数据报“ (datagram) ,datagram是一种逐层增加的设计,用于无连接通讯 下图是一个UDP数据报被封装位一个IP数据包:IPv4字段值位17 表示udp协议 图:udp的IP包 Source:https://notes.shichao.io/tcpv1/ch10 对于udp数据报的组成包含header与payload,udp的header大小为固定的8字节 源端口:可选 目的端口:识别接收信息的进程 Length:udp header + udp payload的长度,最小值为8 checksum:与lenght一样其实是多余的,因为第三层包含了这两个信息 图:udp数据报组成 Source:https://notes....

Linux网络栈

Linux 架构概述 [1] 本章节简单阐述Linux系统的结构,并讨论子系统中的模块之间以及与其他子系统之间的关系。 Linux内核本身鼓励无用,是作为一个操作系统的一部分参与的,只有为一个整体时他才是一个有用的实体,下图展示了Linux操作系统的分层 图:Linux子系统分层图 Source:https://docs.huihoo.com/linux/kernel/a1/index.html 由图可以看出Linux操作系统由四部分组成: 用户应用 OS服务,操作系统的一部分(例如shell)内核编程接口等 内核 硬件控制器,CPU、内存硬件、硬盘和NIC等都数据这部分 Linux内核阐述 Linux内核将所有硬件抽象为一致的接口,为用户进程提供了一个虚拟接口,使用户无需知道计算机上安装了哪些物理硬件即可编写进程,并且Linux支持用户进程的多任务处理,每个进程都可以视作为操作系统的唯一进程独享硬件资源。内核负责维护多个用户进程,并协调其对硬件资源的访问,使得每个进程都可以公平的访问资源,并保证进程间安全。 Linux内核主要为五个子系统组成: 进程调度器(SCHED), 控制进程对 CPU 的访问。调度程序执行策略,确保进程可以公平地访问 CPU。 内存管理器 (MM), 允许多个进程安全地共享操作系统的内存 虚拟文件系统 (VFS),向所有设备提供通用文件接口来抽象出各种硬件设备 网络接口 (NET),提供对多种网络标准与各种网络硬件的访问 进程间通信 (IPC),在单个操作系统上的多种机制进程间通信机制 网络子系统架构 [2] 网络子系统功能主要是允许 Linux 系统通过网络连接到其他系统。支持多种硬件设备,以及可以使用的多种网络协议。网络子系统抽象了这两个实现细节,以便用户进程和其他内核子系统可以访问网络,而不必知道使用什么物理设备或协议。 子系统模块包含 网络设备驱动层 (Network device drivers),网络设备驱动程序与硬件设备通信。每个硬件设备都有对应的设备驱动程序模块。 独立设备接口层(device independent interface),设备独立接口提供了所有硬件设备的统一视图,因此在网络子系统之上的级别无需了解硬件信息 网络协议层 (network protocol),网络协议实现了网络传输的协议 协议独立/无关接口层 (protocol independent interface),提供了独立于硬件设备的网络接口,为内核内其他子系统访问网络时不依赖特定的协议和硬件接口。 系统调用层 (system call) 用于限制用户进程导出资源的访问 网络子系统的结构图如下图所示, 图:网络子系统中的上下文 Source:https://docs.huihoo.com/linux/kernel/a1/index.html 当网络子系统转换为网络栈时,如下图所示 图:ISO Stack与TCP/IP Stack Source:https://www.washington.edu/R870/Networking.html 当然Linux网络子系统是类似于TCP/IP栈的一种结构,当发生一个网络传输时,数据包会按照所经过的层进行封装。例如应用层应用提供了REST API,那么应用将要传输的数据封装为HTTP协议,然后传递给向下的传输层。传输层是TCP协议就会被添加对应的TCP包头。整个封装过程原始包保持不变,会根据所经过层的不同增加固定格式的包头。 图:数据包传输在每层被封装的过程 Source:http://www.embeddedlinux.org.cn/linux_net/0596002556/understandlni-CHP-13-SECT-1.html 对于Linux来说TCP/IP 的五层结构则是构成网络子系统的的核心组件,下图是Linux网络栈结构图 图:Linux网络栈的结构图 Source:https://medium.com/geekculture/linux-networking-deep-dive-731848d791c0 图中橙色部分是位于TCP/IP的五层结构中的应用层,应用层向下通讯通过 system call 与 socket接口进行交互 蓝色部分是位于内核空间,socket向下则是传输层与网络层 最底层是物理层包含网卡驱动与NIC 通过图可以看出,NIC是发送与接收数据包的基本单位,当系统启动时内核通过驱动程序向操作系统注册网卡,当数据包到达网卡时,被放入队列中。内核通过硬中断,运行中断处理程序,为网络帧分配内核数据结构(sk_buff),并将其拷贝到缓冲区中,此为内核与网卡交互的过程。...

科普ebpf

eBPF介绍 eBPF是 Extended Berkeley Packet Filter,主要是用于包过滤的。为什么叫Berkeley Packet Filter 是因为论文出自 Lawrence Berkeley Laboratory(相对的论文可以参考 [1])。“E" 是使BPF不仅仅是包过滤。 eBPF 目前提供的功能不仅仅是包过滤,它是一个允许用户在操作系统内核加载自定义程序的框架,来自于 ”What Is eBPF?“ eBPF is a framework that allows users to load and run custom programs within the kernel of the operating system. That means it can extend or even modify the way the kernel behaves. [2] eBPF验证器 对于如果想改变Linux内核功能需要合并代码到内核或者编写内核模块。前者需要被社区接受,这需要很长一个周期;而后者可以很好的扩展内核功能,但都存在一个问题 ”==安全运行==“ ”安全运行“ 问题包含”漏洞“和“崩溃”,考虑到这些,eBPF为安全运行提供了一个非常不同的方法**:eBPF verifier** ,eBPF verifier 将确保应用只能够在安全情况下被运行。 eBPF verifier 保证了 eBPF 程序运行的 ”安全“ 和 ”验证“...

ch08 文件处理

文件类型 文件是指以字节的形式存储的数据源,使用C语言将文件数据以输出输出的形式处理叫做文件处理。 文件在C语言中以两种形式存在: 文本文件:文本文件是简单的文件类型,这些文件内容以 ASCII 字符格式存储信息。 二进制文件:二进制文件以 0 和 1 的二进制格式存储数据,不是人类可读的文件 文件指针 文件指针 (FILE) 是一种数据类型,是被定义在 stdio.h 中的一种结构体,包含了文件的一些信息 c 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 typedef struct { // fill/empty level of buffer int level; // File status flags unsigned flags; // File descripter char fd; // ungetc char if no buffer unsigned char hold; // buffer size int bsize; // data transfer buffer unsigned char *buffer; // Current active pointer unsigned char *curp; //Temporary file indicator unsigned istemp; //Used for validity checking short token; } FILE; // This is FILE object 文件指针通常被用于处理正在访问的文件,fopen() 是用于打开文件并返回文件的 FILE 指针,而后通过文件只恨进行I/O操作。fopen() 会发生下列事件:...

ch07 复合类型

Overview C语言中复合类型 (composite type) 是指用户自定义类型,通常由多种元素组成的类型,其元素被紧密存储在内存中。C语言常见的复合类型有: 数组 字符串 结构体 联合类型 结构体 [1] 结构体 (structure) 是指用户定义的数据类型,允许将不同类型的多个元素组合在一起,来创建出更复杂的数据类型,类似于数组,但又区别于数组,数组只能保存同类型的元素,而结构体可以保存不同类型的元素。 定义 声明结构体的语法如下 c 1 2 3 4 5 6 struct structureName { dataType memberVariable1; datatype memberVariable2; ... } variable01, variable02...; 这里需要注意的一些地方: struct是关键字,structureName定义的新数据类型,variable{}是作为使用 structureName 声明的新变量名 每个成员方法结尾都是 “;" 而不是逗号 ”," 结构体不能递归 变量可以有多个 例如声明一个学生的结构体,而student是作为一个新的数据类型存在 c 1 2 3 4 5 6 struct student { char name[20]; int roll; char gender; }; Notes:在定义(创建)结构体变量前,结构体成员不会占用内存 声明 使用结构体声明变量 也可以一次性定义结构体和声明变量 c 1 2 3 4 5 6 7 8 9 10 11 12 13 struct student { char name[20]; int roll; char gender; } stu1,stu2; // 结构体名称可以省略 struct { char name[20]; int roll; char gender; } stu1,stu2; 赋值 在声明结构体后,student结构体只是自定义数据结构,要使用还需要进行初始化,或者赋值...

ch06 内存布局

Overview 在编写程序时包含任意指令如,已初始化和未初始化数据,局部变量,函数等都是用于动态分配内存的指令。当程序编译后(默认生成 x.out 文件)这是一个可执行的链接文件( Executable and linking format)。在执行时这些不组织成几部分,包含不同的内存分段 (segments) ELF:这是系统中标准二进制格式,其一些功能包含,动态链接,动态加载,对程序运行时控制。 可以使用 size {ELF_file} 查看被分配的每个段的大小(Linux操作系统); dec 列给出的是这个程序 text + data + bss 段的总大小,用十进制表示 text 段是存储可执行命令的段 data 段包含所有初始化数据,全局与静态变量 BSS 段包含未初始化数据 bash 1 2 3 $ size 1 text data bss dec hex filename 1843 584 8 2435 983 1 Memory Layout in C [1] 在C语言中内存布局模型包含六个部分 命令行参数 (Command Line Arguments) 栈 (Stack) 堆 (Heap) 未初始化数据段 (Uninitialized Data Segment BSS) 已初始化数据段 (Initialized Data Segment) 文本/代码段 (Text/Code Segment) 这6部分结构可以再划分为两种类型:...

ch05 指针

指针 指针声明 [1] 指针/指针变量 (pointer) 是用于存储地址的变量 使用 & 运算符 来访问变量的地址。例如 c 1 2 3 4 5 6 7 #include <stdio.h> void main() { int a = 100; printf("%x", &a); } 输出结果为 16进制的内存地址 c 1 61fe1c 使用地址运算符 * 可以从变量地址中获取变量的值,这个行为被称为间接引用/解引用(indirection/dereferencing)。例如: c 1 2 3 4 5 6 7 8 9 #include <stdio.h> void main() { int a = 100; printf("%d", *(&a)); // 也可以写为,因为*与&优先级相同,从右到左的顺序,所以有没有()意思是相同的 printf("%d", *&a); } 输出结果为 100 指针变量 指针变量是指存储一个变量的地址的变量,可以使用符号 * 来修饰变量,定义语法为:...

ch04 函数

concept [1] 函数 (function) 是执行任务的语句块。 函数的作用: 提高代码的可重用性并减少冗余 代码模块化 代码易读性 使代码模块化 函数的分类 C语言中有两种类型的函数: 标准库函数:C中的内置函数,在头文件中定义 #include <stdio.h> 用户自定义函数:用户自定义的函数 #include "stdio.h" 函数三部曲 C语言中函数分为三个方面,声明(declaration),定义(defining),调用(calling) 声明 声明是让编译器知道函数的名称、参数信息、参数的返回值的类型。 c 1 (type) function_name({type args...}); 隐式声明(implicit) :当在main之后定义的函数而未声明,默认编译器会做隐式声明。 ISO/IEC 9899:1990 中 关于函数声明的部分: 函数在调用前必须有一个可用的声明,如果没有被声明,则该函数默认被隐式声明,该隐式声明没有参数,返回值为int [2] 定义 C中函数定义的语法如下 c 1 2 3 4 return_type function_name(arg1, arg2, ... argn) { function body // 函数中要处理任务的逻辑 } return_type:函数返回值的数据类型 function_name:函数名 arg1, arg2, …argn:参数列表(可选),定义传递给函数的数据类型、顺序和参数的数量。 function body:调用函数时任务处理和执行的语句 调用 调用是指要由编译器执行的函数,可以在任何部分调用 虚函数void 如果函数没有返回值,则使用关键字 void,主要用于两个方面: 打印具体信息供用户阅读的函数 引用参数,函数通常不是用于返回一个内容,而是修改引用参数的,无需返回值 void 关键字使用注意: void仅用于限定函数返回值,函数参数,不可以修饰变量,因为无法对无类型的变量分配指针...

ch03 数组

Array [1] 数组是由单个元素组成的一组数据类型的变量 数组的元素存储在连续的内存位置 声明数组时应提及数组的大小 数组的计数从0开始 数组为一位数组与多维数组 数组首元素的地址与数组地址相同 数组包含 int, float, char, double 数据类型 Declaration and Initialization 表达式 说明 int my_array1[20]; 指定大小,来声明一个有20个元素的int数组 char my_array2[5]; 指定大小,来声明一个有5个元素的char数组 int my_array[] = {100, 200, 300, 400, 500} 声明时初始化一个数组(编译器自动求数组元素个数) int my_array1[5] = {100, 200, 300, 400, 500}; 声明时初始化 int my_array2[5] = {100, 200, 300}; 声明时初始化(剩余未初始化的元素,默认 0 值) int my_array2[5] = {0}; 声明时初始化(声明一个全0值的数组) int arr[10]; arr[0] = 5;arr[1] = 6;arr[2] = 7; 声明数组并初始化值(这种方法为初始化部分的默认值为随机数) char str[] = “zhangsan” 声明一个字符串(字符串是一个char类型数组) Advantages and Disadvantages 缺点**:大小限制**:声明(定义)后是固定的大小,不能通过运行时改变其大小...

ch02 格式化与流程控制

格式化 printf printf() 用于打印消息以及变量的值。 c 1 2 3 4 5 6 7 8 #include<stdio.h> int main() { int a = 24; printf("Welcome! \n"); printf("The value of a : %d",a); getchar(); return 0; } sprintf sprintf() 不打印字符串,是将字符值和格式化结构一并存储在一个数组中。 c 1 2 3 4 5 6 7 8 9 10 11 12 13 int main() { char buffer[50]; int a = 10, b = 20, c; c = a + b; sprintf(buffer, "Sum of %d and %d is %d", a, b, c); // The string "sum of 10 and 20 is 30" is stored // into buffer instead of printing on stdout printf("%s", buffer); return 0; } scanf 从标准输入读取用户输入的...

ch01 变量和数据类型

C语言关键字 [1] ==C语言有32个关键字== auto:定义自动变量,主要是声明变量的生存周期 break, continue : break 语句在遇到最内层循环时立即终止。还用于终止 switch 语句。 case, switch, default:使用 switch 和 case 语句声明一个switch分支 char:用于声明character 类型的变量 const:声明常量 do…while: double: double-precision 浮点数变量类型 float:single-precision 浮点数的变量类型 if, else:声明if/else 条件判断 enum:用于声明枚举类型 extern:关键字声明变量或函数在其声明的文件之外具有外部链接。 for:C 语言的三种循环之一,for循环 goto: 用于将程序的控制权转移到指定的标签 int:声明 integer 类型的变量 short, long, signed, unsigned:是类型修饰符,它们改变基本数据类型的含义以产生新类型。 short int: -32768 to 32767 long int: -2147483648 to 214743648 signed int: -32768 to 32767 unsigned int: 0 to 65535 return: 终止函数并返回值 sizeof:评估变量或常量的大小 register:创建比普通变量快得多的寄存器变量。 static:创建一个静态变量。静态变量的值持续到程序结束。 struct:用于声明结构体。结构体可以包含不同类型的变量。 typedef:用于将类型与标识符显式关联。 union:用于将不同类型的变量分组在一个名称下。 void:没有任何意义,函数修饰为没有返回值,参数修饰为没有参数 volatile:提醒编译器它后面所定义的变量随时都有可能改变 C语言控制语句 ==C语言有9种控制语句== (control statements)...