Linux内核编码风格(译文)
谈谈为 Linux 内核写驱动的编码规范
谈谈为 Linux 内核写驱动的编码规范最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离Linux内核的coding style要求还是差很多。
当初自己对内核文档里的CodingStyle一文只是粗略的浏览,真正写代码的时候在很多细节上会照顾不周。
不过,在不遵守规则的程序员队伍里,我并不是孤独的。
如果去看drivers/staging下的代码,就会发现很多驱动程序都没有严格遵守内核的coding style,而且在很多驱动程序的TODO文件里,都会把"checkpatch.pl fixes"作为自己的目标之一(checkpatch.pl是用来检查代码是否符合coding style的脚本)。
不可否认,coding style是仁者见仁、智者见智的事情。
比如Microsoft所推崇的匈牙利命名法,在Linus看来就是及其脑残(brain damaged)的做法。
也许您并不赞成Linus制定的coding style,但在提交内核驱动这件事上,最好还是以大局为重。
对于这么一个庞大的集市式的开发来说,随意书写代码必将带来严重的可维护性的灾难。
(题图来自:mota.ru)一些辅助工具当代码量达到一定程度时,手动去检查和修改coding style是非常繁琐的工作,幸好,我们还有一些工具可以使用。
scripts/checkpatch.pl这是一个检查代码是否符合内核编码规范的的脚本。
顾名思义,checkpatch是用来检查patch的,默认的调用也确实如此。
如果用来检查原文件,需要加上“-f”的选项。
我们来看一段无聊的代码(文件名为print_msg.c):1.void print_msg(int a)2.{3. switch (a) {4. case 1:5. printf("a == 1\n");6. break;7.8. case 2:9. printf("a == 2\n");10. break;11. }12.}这段代码的coding style是否有问题呢?用checkpatch.pl来检查一下:1.scripts/checkpatch.pl -f print_msg.c检查的结果是:1.ERROR: switch and case should be at the same indent2.#3: FILE: switch.c:3:3.+ switch (a) {4.+ case 1:5.[...]6.+ case 2:7.8.total: 1 errors, 0 warnings, 12 lines checked9.10.switch.c has style problems, please review. If any of theseerrors11.are false positives report them to the maintainer, see12.CHECKPATCH in MAINTAINERS.在Linux内核的coding style里,switch和case要求有相同的缩进。
Linux 内核编译配置选项简介
General setup常规设置Local versio n - append to kernel release在内核版本后面加上自定义的版本字符串(小于64字符),可以用"uname -a"命令看到Automatically append version information to the versio n string 自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持Support for paging of anonymous memory (swap)使用交换分区或者交换文件来做为虚拟内存System V IPCSystem V进程间通信(IPC)支持,许多程序需要这个功能.必选,除非你知道自己在做什么POSIX Message QueuesPOSIX消息队列,这是POSIX IPC中的一部分BSD Process Accounting将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息Export task/process statistics through netlink通过netlink接口向用户空间导出任务/进程的统计信息,与BSD ProcessAccounting的不同之处在于这些统计信息在整个任务/进程生存期都是可用的UTS NamespacesUTS名字空间支持,不确定可以不选Auditing support审计支持,某些内核模块(例如SELinux)需要它,只有同时选择其子项才能对系统调用进行审计Kernel .config support把内核的配置信息编译进内核中,以后可以通过scripts/extract-ikconfig脚本来提取这些信息Cpuset support只有含有大量CPU(大于16个)的SMP系统或NUMA(非一致内存访问)系统才需要它Kernel->user space relay support (formerly relayfs)在某些文件系统上(比如debugfs)提供从内核空间向用户空间传递大量数据的接口Initramfs source file(s)initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白Optimize for size (Look out for broken compilers!)编译时优化内核尺寸(使用"-Os"而不是"-O2"参数编译),有时会产生错误的二进制代码Enable extended accounting over taskstats收集额外的进程统计信息并通过taskstats接口发送到用户空间Configure standard kernel features (for small systems)配置标准的内核特性(为小型系统)Include all symbols in kallsyms在kallsyms中包含内核知道的所有符号,内核将会增大300KDo an extra kallsyms pass除非你在kallsyms中发现了bug并需要报告这个bug才打开该选项Loadable module support可加载模块支持Enable loadable module support打开可加载模块支持,如果打开它则必须通过"make modules_install"把内核模块安装在/lib/modules/中Module unloading允许卸载已经加载的模块Forced module unloading允许强制卸载正在使用中的模块(比较危险)Module versioning support允许使用其他内核版本的模块(可能会出问题)Source checksum for all modules为所有的模块校验源码,如果你不是自己编写内核模块就不需要它Block layer块设备层Enable the block layer块设备支持,使用硬盘/USB/SCSI设备者必选Support for Large Block Devices仅在使用大于2TB的块设备时需要Support for tracing block io actions块队列IO跟踪支持,它允许用户查看在一个块设备队列上发生的所有事件,可以通过blktrace程序获得磁盘当前的详细统计数据Support for Large Single Files仅在可能使用大于2TB的文件时需要IO SchedulersIO调度器Anticipatory I/O scheduler假设一个块设备只有一个物理查找磁头(例如一个单独的SATA硬盘),将多个随机的小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.适用于大多数环境,特别是写入较多的环境(比如文件服务器)Deadline I/O scheduler使用轮询的调度器,简洁小巧,提供了最小的读取延迟和尚佳的吞吐量,特别适合于读取较多的环境(比如数据库)CFQ I/O scheduler使用QoS策略为所有任务分配等量的带宽,避免进程被饿死并实现了较低的延迟,可以认为是上述两种调度器的折中.适用于有大量进程的多用户系统Default I/O scheduler默认IO调度器Processor type and features中央处理器(CPU)类型及特性Symmetric multi-processing support对称多处理器支持,如果你有多个CPU或者使用的是多核CPU就选上.此时"Enhanced Real Time Clock Support"选项必须开启,"Advanced PowerManagement"选项必须关闭Subarchitecture Type处理器的子架构,大多数人都应当选择"PC-compatible"Processor family处理器系列,请按照你实际使用的CPU选择Generic x86 support通用x86支持,如果你的CPU能够在上述"Processor family"中找到就别选HPET Timer SupportHPET是替代8254芯片的新一代定时器,i686及以上级别的主板都支持,可以安全的选上Maximum number of CPUs支持的最大CPU数,每增加一个内核将增加8K体积SMT (Hyperthreading) scheduler support支持Intel的超线程(HT)技术Multi-core scheduler support针对多核CPU进行调度策略优化Preemption Model内核抢占模式No Forced Preemption (Server)适合服务器环境的禁止内核抢占Voluntary Kernel Preemption (Desktop)适合普通桌面环境的自愿内核抢占Preemptible Kernel (Low-Latency Desktop)适合运行实时程序的主动内核抢占Preempt The Big Kernel Lock可以抢占大内核锁,应用于实时要求高的场合,不适合服务器环境Machine Check Exception让CPU检测到系统故障时通知内核,以便内核采取相应的措施(如过热关机等) Check for non-fatal errors on AMD Athlon/Duron / IntelPentium 4每5秒检测一次这些cpu的非致命错误并纠正它们,同时记入日志check for P4 thermal throttling interrupt当P4的cpu过热时显示一条警告消息Enable VM86 support虚拟X86支持,在DOSEMU下运行16-bit程序或XFree86通过BIOS初始化某些显卡的时候才需要Toshiba Laptop supportToshiba笔记本模块支持Dell laptop supportDell笔记本模块支持Enable X86 board specific fixups for reboot修正某些旧x86主板的重起bug,这种主板基本绝种了/dev/cpu/microcode - Intel IA32 CPU microcode support使用不随Linux内核发行的IA32微代码,你必需有IA32微代码二进制文件,仅对Intel的CPU有效/dev/cpu/*/msr - Model-specific register support在多cpu系统中让特权CPU访问x86的MSR寄存器/dev/cpu/*/cpuid - CPU informatio n support能从/dev/cpu/x/cpuid获得CPU的唯一标识符(CPUID)Firmware Drivers固件驱动程序BIOS Enhanced Disk Drive calls determine boot disk 有些BIOS支持从某块特定的硬盘启动(如果BIOS不支持则可能无法启动),目前大多数BIOS还不支持BIOS update support for DELL systems via sysfs 仅适用于DELL机器Dell Systems Management Base Driver仅适用于DELL机器High Memory Support最高内存支持,总内存小于等于1G的选"off",大于4G的选"64G"Memory split如果你不是绝对清楚自己在做什么,不要改动这个选项Memory model一般选"Flat Memory",其他选项涉及内存热插拔64 bit Memory and IO resources使用64位的内存和IO资源Allocate 3rd-level pagetables from highmem在内存很多(大于4G)的机器上将用户空间的页表放到高位内存区,以节约宝贵的低端内存Math emulation数学协处理器仿真,486DX以上的cpu就不要选它了MTRR (Memory Type Range Register) support打开它可以提升PCI/AGP总线上的显卡2倍以上的速度,并且可以修正某些BIOS错误Boot from EFI supportEFI是一种可代替传统BIOS的技术(目前的Grub/LILO尚不能识别它),但是现在远未普及Enable kernel irq balancing让内核将irq中断平均分配给多个CPU以进行负载均衡,但是要配合irqbanlance守护进程才行Use register arguments使用"-mregparm=3"参数编译内核,将前3个参数以寄存器方式进行参数调用,可以生成更紧凑和高效的代码Enable seccomp to safely compute untrusted bytecode只有嵌入式系统可以不选Timer frequency内核时钟频率,桌面推荐"1000 HZ",服务器推荐"100 HZ"或"250 HZ"kexec system call提供kexec系统调用,可以不必重启而切换到另一个内核kernel crash dumps被kexec启动后产生内核崩溃转储Physical address where the kernel is loaded内核加载的物理地址,除非你知道自己在做什么,否则不要修改.在提供kexec系统调用的情况下可能要修改它Support for hot-pluggable CPUs对热插拔CPU提供支持Compat VDSO support如果Glibc版本大于等于2.3.3就不选,否则就选上Power management options电源管理选项Power Management support电源管理有APM和ACPI两种标准且不能同时使用.即使关闭该选项,X86上运行的Linux也会在空闲时发出HLT指令将CPU进入睡眠状态Legacy Power Management API传统的电源管理API,比如软关机和系统休眠等接口Power Management Debug Support仅供调试使用Driver model /sys/devices/.../power/state files 内核帮助文档反对使用该选项,即将被废除ACPI (Advanced Configuration and Power Interface) Support必须运行acpid守护程序ACPI才能起作用.ACPI是为了取代APM而设计的,因此应该尽量使用ACPI而不是APMAC Adapter如果你的系统可以在AC和电池之间转换就可以选Battery通过/proc/acpi/battery向用户提供电池状态信息,用电池的笔记本可以选Button守护程序捕获Power,Sleep,Lid按钮事件,并根据/proc/acpi/event做相应的动作,软件控制的poweroff需要它Video仅对集成在主板上的显卡提供ACPI2.0支持,且不是所有集成显卡都支持Generic Hotkey统一的热键驱动,建议不选Fan允许通过用户层的程序来对系统风扇进行控制(开,关,查询状态),支持它的硬件并不多Dock支持由ACPI控制的集线器(docking stations)Processor让ACPI处理空闲状态,并使用ACPI C2和C3处理器状态在空闲时节省电能,同时它还被cpufreq的"Performance-state drivers"选项所依赖Thermal Zone系统温度过高时可以利用ACPI thermal zone及时调整工作状态以避免你的CPU被烧毁ASUS/Medio n Laptop Extras ASUS笔记本专用,以提供额外按钮的支持,用户可以通过/proc/acpi/asus来打开或者关闭LCD的背光/调整亮度/定制LED的闪烁指示等功能IBM ThinkPad Laptop Extras IBM ThinkPad专用Toshiba Laptop Extras Toshiba笔记本专用Disable ACPI for systemsbefore Jan 1st this year 输入四位数的年份,在该年的1月1日前不使用ACPI的功能("0"表示一直使用)Debug Statements 详细的ACPI调试信息,不搞开发就别选Power ManagementTimer Support 这个Timer在所有ACPI兼容的平台上都可用,且不会受PM功能的影响,建议总是启用它.如果你在kernel log中看到了'many lost ticks'那就必须启用它ACPI0004,PNP0A05and PNP0A06Container Driver 支持内存和CPU的热插拔Smart BatterySystem 支持依赖于I2C的"智能电池".这种电池非常老旧且罕见,还与当前的ACPI标准兼容性差APM (Advanced Power Management) BIOS SupportAPM在SMP机器上必须关闭,一般来说当前的笔记本都支持ACPI,所以应尽量关闭该该选项Ignore USER SUSPEND只有NEC Versa M系列的笔记本才需要选择这一项Enable PM at boot time系统启动时即启用APM,选上这个选项能让系统自动的进行电源管理,但常常导致启动时死机Make CPU Idle calls when idle系统空闲时调用空闲指令(halt),只有老式的CPU才需要选它,且对于SMP系统必须关闭Enable console blanking using APM在屏幕空白时关闭LCD背光,事实上对所有的笔记本都无效RTC stores time in GMT将硬件时钟应该设为格林威治时间,否则视为本地时间.建议你使用GMT,这样你无须为时区的改变而担心Allow interrupts during APM BIOS calls 允许APM的BIOS调用时中断,IBM Thinkpad的一些新机器需要这项.如果休眠时挂机(包括睡下去就醒不来),可以试试它Use real mode APM BIOS call to power off 此驱动为某些有Bug的BIOS准备,如果你的系统不能正常关机或关机时崩溃,可以试试它CPU Frequency scaling允许动态改变CPU主频,达到省电和降温的目的,必须同时启用下面的一种governor才行Enable CPUfreq debugging允许对CPUfreq进行调试CPU frequency translation statistics通过sysfs文件系统输出CPU频率变换的统计信息CPU frequency translation statistics details输出详细的CPU频率变换统计信息Default CPUFreq governor默认的CPU频率调节器'performance' governor'性能'优先,静态的将频率设置为cpu支持的最高频率'powersave' governor'节能'优先,静态的将频率设置为cpu支持的最低频率'userspace' governor for userspace frequencyscaling既允许手动调整cpu频率,也允许用户空间的程序动态的调整cpu频率(需要额外的调频软件,比如cpufreqd)'ondemand' cpufreq policy governor '立即响应',周期性的考察CPU负载并自动的动态调整cpu频率(不需要额外的调频软件),适合台式机'conservative' cpufreq governor '保守',和'ondemand'相似,但是频率的升降是渐变式的(幅度不会很大),更适合用于笔记本/PDA/AMD64环境ACPI Processor P-States driver 将ACPI2.0的处理器性能状态报告给CPUFreq processor drivers以决定如何调整频率,该选项依赖于ACPI->Processor{省略的部分请按照自己实际使用的CPU选择}/proc/acpi/processor/../performance interface内核帮助文档反对使用该选项,即将被废除Relaxed speedstep capabilitychecks放松对系统的speedstep兼容性检查,仅在某些老旧的Intel系统上需要打开Bus options (PCI, PCMCIA, EISA, MCA, ISA)总线选项PCI supportPCI支持,如果使用了PCI或PCI Express设备就必选PCI access modePCI访问模式,强列建议选"Any"(系统将优先使用"MMConfig",然后使用"BIOS",最后使用"Direct"检测PCI设备)PCI Express supportPCI Express支持(目前主要用于显卡和千兆网卡)PCI Express Hotplug driver如果你的主板和设备都支持PCI Express热插拔就可以选上Use po lling mechanism for hot-plug events对热插拔事件采用轮询机制,仅用于测试目的Root Port Advanced Error Reporting support由PCI Express AER驱动程序处理发送到Root Port的错误信息Message Signaled Interrupts (MSI and MSI-X) PCI Express支持两类中断:INTx使用传统的IRQ中断,可以与现行的PCI总线的驱动程序和操作系统兼容;MSI则是通过inbound Memory Write触发和发送中断,更适合多CPU系统.可以使用"pci=nomsi"内核引导参数关闭MSIPCI Debugging将PCI调试信息输出到系统日志里Interrupts on hypertransport devices允许本地的hypertransport设备使用中断ISA support现在基本上没有ISA的设备了,如果你有就选吧MCA support微通道总线,老旧的IBM的台式机和笔记本上可能会有这种总线NatSemi SCx200 support在使用AMD Geode处理器的机器上才可能有PCCARD (PCMCIA/CardBus) supportPCMCIA卡(主要用于笔记本)支持Enable PCCARD debugging仅供调试16-bit PCMCIA support一些老的PCMCIA卡使用16位的CardBus32-bit CardBus support当前的PCMCIA卡基本上都是32位的CardBusCardBus yenta-compatible bridge support使用PCMCIA卡的基本上都需要选择这一项,子项请按照自己实际使用的PCMCIA卡选择{省略的部分请按照自己实际使用的PCMCIA卡选择} PCI Hotplug SupportPCI热插拔支持,如果你有这样的设备就到子项中去选吧Executable file formats可执行文件格式Kernel support for ELF binariesELF是开放平台下最常用的二进制文件格式,支持动态连接,支持不同的硬件平台.除非你知道自己在做什么,否则必选Kernel support for a.out and ECOFF binaries早期UNIX系统的可执行文件格式,目前已经被ELF格式取代Kernel support for MISC binaries允许插入二进制的封装层到内核中,使用Java,.NET,Python,Lisp等语言编写的程序时需要它Networking网络Networking options网络选项Network packet debugging在调试不合格的包时加上额外的附加信息,但在遇到Dos攻击时你可能会被日志淹没Packet socket这种Socket可以让应用程序(比如tcpdump,iptables)直接与网络设备通讯,而不通过内核中的其它中介协议Packet socket: mmapped IO让Packet socket驱动程序使用IO映射机制以使连接速度更快Unix domain sockets一种仅运行于本机上的效率高于TCP/IP的Socket,简称Unix socket.许多程序都使用它在操作系统内部进行进程间通信(IPC),比如X Window和syslogTransformatio n user configuratio n interface为IPsec(可在ip层加密)之类的工具提供XFRM用户配置接口支持Transformatio n sub po licy supportXFRM子策略支持,仅供开发者使用PF_KEY sockets用于可信任的密钥管理程序和操作系统内核内部的密钥管理进行通信,IPsec依赖于它TCP/IP networkingTCP/IP协议当然要选IP: multicasting群组广播,似乎与网格计算有关,仅在使用MBONE的时候才需要IP: advanced router高级路由,如果想做一个路由器就选吧IP: policy routing策略路由IP: equal cost multipath用于路由的基于目的地址的负载均衡IP: verbose route monitoring显示冗余的路由监控信息IP: kernel level autoconfiguratio n在内核启动时自动配置ip地址/路由表等,需要从网络启动的无盘工作站才需要这个东西IP: tunnelingIP隧道,将一个IP报文封装在另一个IP报文内的技术IP: GRE tunnels over IP基于IP的GRE(通用路由封装)隧道IP: multicast routing多重传播路由IP: ARP daemon support这东西尚处于试验阶段就已经被废弃了IP: TCP syncookie support抵抗SYN flood攻击的好东西,要启用它必须同时启用/proc文件系统和"Sysctl support",然后在系统启动并挂载了/proc之后执行"echo1 >/proc/sys/net/ipv4/tcp_syncookies"命令IP: AH transformatio nIPsec验证头(AH)实现了数据发送方的验证处理,可确保数据既对于未经验证的站点不可用也不能在路由过程中更改IP: ESP transformationIPsec封闭安全负载(ESP)实现了发送方的验证处理和数据加密处理,用以确保数据不会被拦截/查看或复制IP: IPComp transformationIPComp(IP静荷载压缩协议),用于支持IPsecIP: IPsec transport modeIPsec传输模式,常用于对等通信,用以提供内网安全.数据包经过了加密但IP头没有加密,因此任何标准设备或软件都可查看和使用IP头IP: IPsec tunnel modeIPsec隧道模式,用于提供外网安全(包括虚拟专用网络).整个数据包(数据头和负载)都已经过加密处理且分配有新的ESP头/IP头和验证尾,从而能够隐藏受保护站点的拓扑结构IP: IPsec BEET modeIPsec BEET模式INET: socket monitoring interfacesocket监视接口,一些Linux本地工具(如:包含ss的iproute2)需要使用它TCP: advanced congestio n control高级拥塞控制,如果没有特殊需求(比如无线网络)就别选了,内核会自动将默认的拥塞控制设为"Cubic"并将"Reno"作为候补IP: Virtual Server ConfigurationIP虚拟服务器允许你基于多台物理机器构建一台高性能的虚拟服务器,不玩集群就别选了The IPv6 protocol你要是需要IPv6就选吧NetLabel subsystem supportNetLabel子系统为诸如CIPSO与RIPSO之类能够在分组信息上添加标签的协议提供支持,如果你看不懂就别选了Security Marking对网络包进行安全标记,类似于nfmark,但主要是为安全目的而设计,如果你不明白的话就别选Network packet filtering (replaces ipchains)Netfilter可以对数据包进行过滤和修改,可以作为防火墙("packet filter"或"proxy-based")或网关(NAT)或代理(proxy)或网桥使用.选中此选项后必须将"Fast switching"关闭,否则将前功尽弃Network packet filtering debugging仅供开发者调试Netfilter使用Bridged IP/ARP packets filtering如果你希望使用一个针对桥接的防火墙就打开它Core Netfilter Configuration核心Netfilter配置(当包流过Chain时如果match某个规则那么将由该规则的target来处理,否则将由同一个Chain中的下一个规则进行匹配,若不match所有规则那么最终将由该Chain的policy进行处理)Netfilter netlink interface允许Netfilter在与用户空间通信时使用新的netlink接口.netlink Socket是Linux用户态与内核态交流的主要方法之一,且越来越被重视.Netfilter NFQUEUE over NFNETLINK interface通过NFNETLINK接口对包进行排队Netfilter LOG over NFNETLINK interface通过NFNETLINK接口对包记录.该选项废弃了ipt_ULOG和ebg_ulog机制,并打算在将来废弃基于syslog的ipt_LOG和ip6t_LOG模块Layer 3 Independent Connection tracking独立于第三层的链接跟踪,通过广义化的ip_conntrack支持其它非IP协议的第三层协议Netfilter Xtables support如果你打算使用ip_tables,ip6_tables,arp_tables之一就必须选上"CLASSIFY" target support允许为包设置优先级,一些排队规则(atm,cbq,dsmark,pfifo_fast,htb,prio)需要使用它"CONNMARK" target support类似于"MARK",但影响的是连接标记的值"DSCP" target support允许对ip包头部的DSCP(Differentiated Services Codepoint)字段进行修改,该字段常用于Qos"MARK" target support允许对包进行标记(通常配合ip命令使用),这样就可以改变路由策略或者被其它子系统用来改变其行为"NFQUEUE" target Support用于替代老旧的QUEUE(iptables内建的target之一),因为NFQUEUE能支持最多65535个队列,而QUEUE只能支持一个"NOTRACK" target support允许规则指定哪些包不进入链接跟踪/NAT子系统"SECMARK" target support允许对包进行安全标记,用于安全子系统"CONNSECMARK" target support针对链接进行安全标记,同时还会将连接上的标记还原到包上(如果链接中的包尚未进行安全标记),通常与SECMARK target联合使用"comment" match support允许你在iptables规则集中加入注释"connbytes" per-connection counter match support允许针对单个连接内部每个方向(进/出)匹配已经传送的字节数/包数"connmark" connection mark match support允许针对每个会话匹配先前由"CONNMARK"设置的标记值"conntrack" connection tracking match support连接跟踪匹配,是"state"的超集,它允许额外的链接跟踪信息,在需要设置一些复杂的规则(比如网关)时很有用"DCCP" protocol match supportDCCP是打算取代UDP的新传输协议,它在UDP的基础上增加了流控和拥塞控制机制,面向实时业务"DSCP" match support允许对IP包头的DSCP字段进行匹配"ESP" match support允许对IPSec包中的ESP头进行匹配,使用IPsec的话就选上吧"helper" match support加载特定协议的连接跟踪辅助模块,由该模块过滤所跟踪的连接类型的包,比如ip_conntrack_ftp模块"length" match support允许对包的长度进行匹配"limit" match support允许根据包的进出速率进行规则匹配,常和"LOG target"配合使用以抵抗某些Dos攻击"mac" address match support允许根据以太网的MAC进行匹配,常用于无线网络环境"mark" match support允许对先前由"MARK"标记的特定标记值进行匹配IPsec "policy" match support使用IPsec就选上吧Multiple port match support允许对TCP或UDP包同时匹配多个端口(通常情况下只能匹配一个端口)"physdev" match support允许对到达的或将要离开的物理桥端口进行匹配"pkttype" packet type match support允许对封包目的地址类别(广播/群播/直播)进行匹配"quota" match support允许对总字节数的限额值进行匹配"realm" match support允许对iptables中的路由子系统中的realm值进行匹配"sctp" protocol match support流控制传输协议(SCTP),十年以后也许能够普及的东西"state" match support这是对包进行分类的有力工具,它允许利用连接跟踪信息对连接中处于特定状态的包进行匹配"statistic" match support允许根据一个给定的百分率对包进行周期性的或随机性的匹配"string" match support允许根据包所承载的数据中包含的特定字符串进行匹配"tcpmss" match support允许根据TCP SYN包头中的MSS(最大分段长度)选项的值进行匹配IP: Netfilter Configuration针对IPv4的Netfilter配置Connection tracking (required for masq/NAT)链接跟踪.可用于报文伪装或地址转换,也可用于增强包过滤能力Connection tracking flow accounting允许针对每个连接记录已经传送的字节/包数,常用于connbytes matchConnection mark tracking support允许对连接进行标记,与针对单独的包进行标记的不同之处在于它是针对连接流的.CONNMARK target和connmark match需要它的支持Connection tracking security mark support允许对连接进行安全标记,通常这些标记包(SECMARK)复制到其所属连接(CONNSECMARK),再从连接复制到其关联的包(SECMARK)Connection tracking events连接跟踪事件支持.如果启用这个选项,连接跟踪代码将提供一个notifier链,它可以被其它内核代码用来获知连接跟踪状态的改变Connection tracking netlink interface支持基于netlink的用户空间接口SCTP protocol connection tracking supportSCTP是IP网面向多媒体通信的新一代的流控制传输协议FTP protocol supportFTP协议IRC protocol supportIRC协议是一种用来实时聊天协议,用过mIRC的人应当不陌生NetBIOS name service protocol supportNetBIOS名字服务协议TFTP protocol supportTFTP是基于UDP的比FTP简单的文件传输协议Amanda backup protocol supportAmanda备份协议PPTP protocol support点对点隧道协议(PPTP)是一种支持多协议虚拟专用网络的网络技术,ADSL用户对它应该很熟悉H.323 protocol supportITU-T提出的用于IP电话的协议SIP protocol supportIETE提出的用于IP电话的协议IP Userspace queueing via NETLINK已废弃IP tables support (required for filtering/masq/NAT)要用iptables就肯定要选上IP range match support允许对ip地址的范围进行匹配TOS match support允许对ip包头的TOS(Type Of Service)字段进行匹配recent match support可以创建一个或多个刚刚使用过的ip地址列表,然后根据这些列表进行匹配ECN match support允许对TCP/IP包头的ECN(Explicit Congestion Notification)字段进行匹配.ECN是一种显式拥塞通知技术,它不但要求路由器支持而且要求端到端主机的支持,其基本思想是当路由器发生早期拥塞时不是丢弃包而是尽量对包进行标记,接收方接到带有ECN提示的包时,通知发送方网络即将发生拥塞,也就是它通过对包的标记提示TCP源即将发生拥塞,从而引发拥塞避免算法AH match support允许对IPSec包头的AH字段进行匹配TTL match support允许对ip包头的TTL(生存期)字段进行匹配Owner match support允许对本地生成的包按照其宿主(user,group,process,session)进行匹配address type match support允许对地址类型(单播,本地,广播)进行匹配hashlimit match support是limit的升级,它基于你选择的ip地址与/或端口动态的创建以limit为桶(bucket)的哈希表.它可以创建诸如"为每个特定的目标IP分配10kpps"或"允许每个特定的源IP分配500pps"之类的规则Packet filtering定义filter表以允许对包进行过滤REJECT target support允许返回一个ICMP错误而不是简单的丢弃包LOG target support允许将符合条件的包头信息通过syslog进行记录ULOG target support透过netlink socket将符合条件的封包交给用户空间的ulogd守护进程.反对使用该选项,因为它已经被NETFILTER_NETLINK_LOG代替TCPMSS target support允许修改TCP包头中的MSS(最大分段长度)选项值Full NAT允许进行伪装/端口转发以及其它的NAT功能,仅在你需要使用iptables中的nat 表时才需要选择Packet mangling在iptables中启用mangle表以便对包进行各种修改,常用于改变包的路由raw table support (required for NOTRACK/TRACE)在iptables中添加一个'raw'表,该表在netfilter框架中非常靠前,并在PREROUTING和OUTPUT链上有钩子,从而可以对收到的数据包在连接跟踪前进行处理ARP tables supportARP表支持.只有在局域网中才有ARP欺骗问题,另外路由器也会遭到ARP欺骗ARP packet filteringARP包过滤.对于进入和离开本地的ARP包定义一个filter表,在桥接的情况下还可以应用于被转发ARP包ARP payload mangling允许对ARP包的荷载部分进行修改,比如修改源和目标物理地址IPv6: Netfilter Configuration针对IPv6的Netfilter配置,需要的话可以参考前面IPv4的Netfilter配置进行选择DECnet: Netfilter Configuratio n针对DECnet的Netfilter配置Bridge: Netfilter Configuration针对桥接的Netfilter配置DCCP Configuratio n数据报拥塞控制协议在UDP的基础上增加了流控和拥塞控制机制,使数据报协议能够更好地用于流媒体业务的传输SCTP Configuration流控制传输协议是一种新兴的传输层协议.TCP协议一次只能连接一个IP地址而在SCTP协议一次可以连接多个IP地址且可以自动平衡网络负载,一旦某一个IP 地址失效会自动将网络负载转移到其他IP地址上TIPC Configuration透明内部进程间通信协议,以共享内存为基础实现任务和资源的调度,专门用于内部集群通信Asynchronous Transfer Mode (ATM)异步传输模式(ATM)支持802.1d Ethernet Bridging802.1d以太网桥802.1Q VLAN Support802.1Q虚拟局域网DECnet SupportDECnet是一种很生僻的协议ANSI/IEEE 802.2 LLC type 2 Support看不懂可以不选The IPX protocolIPX协议Appletalk protocol support与Mac机器通信的协议CCITT X.25 Packet Layer大约没人需要这东西LAPB Data Link Driver大约没人需要这东西。
Linux内核源代码解读
最初,Linux核心的最开始部分是用8086汇编语言编写的。当开始运行时,核心将自己装入到绝对地址0x90000(576K; 1001,0000,0000,0000,0000),再将其后的2k字节装入到地址0x90200(576.5k; 1001,0000,0010,0000,0000)处,最后将核心的其余部分装入到0x10000(64k; 1,0000,0000,0000,0000).
mov cx,#256
sub si,si
| 寄存器清零
sub di,di
| 寄存器清零
rep
movw
mov bx,#0x0007
| page 0, attribute 7 (normal)
mov bp,#msg1
| 显示Loading System ...
mov ax,#0x1301
| 将由SI作为指针的源串中的一个字节或字或双字传送到由DI作为指针的目的串中,并根据标志DF值自动修
| 改这两个指针以指向串中下一项。若带有前缀REP,则重复执行这一传送,直到CX寄存器等于零为止。
| 源地址:DS=0x07C0(31K;0111,1100,0000,0000);
| 目的地址:ES=0x9000(576K;1001,0000,0000,0000,0000)
提问者: Linux探索者 - 一级
答复 共 1 条
检举
系统初始化程序 boot.s 的分析 [转]
系统初始化程序 boot.s 的分析:
阚志刚,2000/03/20下午,在前人的基础之上进行整理完善
**********************************************************************************************
linux 的编码格式
linux 的编码格式**Linux 编码格式简介**在Linux 系统中,编码格式起着至关重要的作用。
它是一种将字符转换为二进制的方式,以便在计算机内部进行存储和传输。
了解Linux 编码格式对于更好地使用这个强大的操作系统至关重要。
**Linux 常用编码格式对比**Linux 系统中存在多种编码格式,其中最常用的有ASCII、UTF-8、GBK 等。
1.ASCII:这是一种最基本的编码格式,主要应用于英文和数字。
然而,它在处理中文等复杂字符时存在局限性。
2.UTF-8:这是一种广泛应用于Linux 的编码格式,它可以表示几乎所有的Unicode 字符。
UTF-8 具有良好的兼容性和跨平台性,是目前Linux 系统中最为推荐的编码格式。
3.GBK:这是一种针对中文设计的编码格式,适用于简体中文环境。
在Linux 系统中,GBK 编码可以满足大部分中文文本的处理需求。
**如何选择合适的编码格式**在选择编码格式时,需要考虑以下几个方面:1.目标用户:根据您的读者群体,选择他们熟悉的编码格式。
例如,面向国内用户,可以选择GBK 编码;面向国际用户,可以选择UTF-8 编码。
2.文件兼容性:确保所选编码格式与其他操作系统和软件的兼容性。
例如,使用UTF-8 编码可以确保在各种操作系统和设备上都能正常显示文本。
3.存储空间:较小的编码格式如ASCII 和GBK 占用存储空间较少,但处理字符范围有限;UTF-8 编码虽然兼容性较好,但占用存储空间相对较大。
4.文本处理需求:根据您的文本处理需求,选择合适的编码格式。
例如,如果您需要处理大量特殊字符或Unicode 字符,可以选择UTF-8 编码。
**编码格式在Linux 中的应用场景**编码格式在Linux 系统中有着广泛的应用场景,如:1.文本编辑器:不同的编码格式可以在文本编辑器中显示和编辑不同类型的文本。
2.编程语言:编程语言中的变量名、注释和字符串常使用编码格式进行存储和处理。
linux内核编译 menuconfig详解
内核版本 2.6.32[*]Prompt for development and/or incomplete code/drivers显示尚在开发中或尚未完成的代码与驱动.你应该选择它,因为有许多设备可能必需选择这个选项才能进行配置,实际上它是安全的。
这个选项同样会让一些老的驱动的可用。
如果你选了Y,你将会得到更多的阿尔法版本的驱动和代码的配置菜单。
()Local version - append to kernel release在内核版本后面加上自定义的版本字符串(小于64字符),可以用"uname -a"命令看到[ ]Automatically append version information to the version string自动生成版本信息。
这个选项会自动探测你的内核并且生成相应的版本,使之不会和原先的重复。
这需要Perl的支持。
由于在编译的命令make-kpkg 中我们会加入- –append-to-version 选项来生成自定义版本,所以这里选N。
Kernel compression mode (Gzip)内核压缩模式选baip2gzip用于UNIX系统的文件压缩。
后缀为.gz的文件。
现今已经成为Internet 上使用非常普遍的一种数据压缩格式,或者说一种文件格式。
HTTP协议上的GZIP编码是一种用来改进WEB应用程序性能的技术。
大流量的WEB站点常常使用GZIP压缩技术来让用户感受更快的速度。
bzip2是一个基于Burrows-Wheeler 变换的无损压缩软件,压缩效果比传统的LZ77/LZ78压缩算法来得好。
它是一款免费软件。
bzip2能够进行高质量的数据压缩。
它利用先进的压缩技术,能够把普通的数据文件压缩10%至15%,压缩的速度和解压的效率都非常高!支持现在大多数压缩格式,包括tar、gzip 等等。
lzma是一个Deflate和LZ77算法改良和优化后的压缩算法,开发者是Igor Pavlov,2001年被首次应用于7-Zip压缩工具中,是 2001年以来得到发展的一个数据压缩算法。
Linux内核编译说明
Linux内核编译说明1.Linux内核源码结构:内核源码中主要包含以下子目录:arch :包含了与体系结构相关的代码对应于每一个支持的体系结构,有一个相应的子目录如i386、arm、alpha等。
其每个体系结构子目录下包含几个主要的子目录:kernel :包含与体系结构相关的内核代码mm :包含与体系结构相关的内存管理代码lib :包含与体系结构相关的库代码documentation:包含内核的文档drivers :包含设备驱动代码。
每类设备有相应的子目录,如char 、block、net等fs :包含文件系统的代码。
每个支持的文件系统有相应的子目录,如ext2、proc等include :内核头文件,对每一种体系结构,分别有相应的子目录。
init :包含内核初始化代码lib :包含内核的库代码mm :包含内存管理代码kernel :包含内核管理代码net :包含网络部分的代码2.系统引导的过程在pc机上系统启动过程:系统加电以后bois对系统完成监测设置后将控制权交给硬盘上MBR中的BootLoader 在这里即是lilo或grub等。
BootLoader 将操作系统代码调入内存,然后将控制权交给arch/i386/boot中的Setup.S 这段程序。
Setup.S 这段程序在386实模式下对系统进行基本的检测和设置后转入保护模式把控制权交给Head.SHead.S 建立内存管理和中断管理的框架后调用init/main.c中的start_kernel()函数在start_kernel执行完成后用户就可以登录和使用linux了。
Start_kernel()函数在init/main.c 中定义。
Start_kernel的流程中的主要步骤:setup_arch(&command_line); 用于和处理器、内存等最基本的硬件相关部分的初始化。
在arch/i386/kernel/setup.c 中定义;parse_options(command_line); 把启动时得到的参数从命令行的字符串中分离出来并赋给相应的变量。
linux 的编码格式
linux 的编码格式Linux的编码格式简介:Linux是一种开源操作系统,广泛应用于各个领域。
在Linux系统中,编码格式是一个关键的概念,它决定了如何表示和存储文本数据。
本文将介绍常见的Linux编码格式及其特点,以及在使用Linux系统时应该注意的问题。
一、ASCII编码ASCII(American Standard Code for Information Interchange)是最早的字符编码标准,在计算机中使用7位二进制数来表示字符。
它定义了128个字符,包括大写和小写字母、数字以及一些常见的符号,如英文标点符号和控制字符。
由于ASCII编码只能表示有限的字符集合,不能满足国际化需求,因此逐渐被更全面的编码格式所取代。
二、UTF-8编码UTF-8(Unicode Transformation Format-8bit)是一种可变长度的Unicode编码标准,支持全球范围内的字符集。
UTF-8编码在Linux系统中被广泛使用,因为它能够兼容ASCII编码。
UTF-8使用1至4个字节来表示一个字符,具备良好的兼容性和可扩展性。
它可以表示几乎所有的字符,包括汉字、拉丁字母、希腊字母等。
UTF-8编码是Linux系统默认的字符编码格式。
三、GBK编码GBK编码是中国国家标准的字符集,它是对GB2312编码的扩充,能够覆盖更多的中文字符。
GBK编码使用2个字节表示一个字符,其中包含了21003个汉字和符号以及部分非汉字字符。
在Linux系统中,如果需要处理中文字符的文本数据,可以选择使用GBK编码来存储和表示。
四、其他编码格式除了ASCII、UTF-8和GBK编码外,Linux还支持其他一些编码格式,如UTF-16、ISO-8859等。
这些编码格式通常用于特定的情况和需求,比如在处理特定语言或特定文件格式时使用。
五、在Linux系统中选择编码格式的注意事项1. 考虑文本数据的应用场景和需求。
Linux内核编程规范与代码风格
Linux内核编程规范与代码风格这是⼀篇阐述Linux内核编程代码风格的⽂档,译者以学习为⽬的进⾏翻译。
1 缩进Tab的宽度是⼋个字符,因此缩进的宽度也是⼋个字符。
有些异教徒想让缩进变成四个字符,甚⾄是两个字符的宽度,这些⼈和那些把 PI 定义为 3 的⼈是⼀个路⼦的。
注意:缩进的全部意义在于清晰地定义语句块的开始与结束,特别是当你盯着屏幕20个⼩时之后,你会发现长的缩进宽度的作⽤。
现在有些⼈说⼋个字符的宽度太宽了,这会让代码往右移很远,在⼀块⼋⼗字符宽的屏幕上,这样的代码会很难阅读。
对此的回答是,如果你写的代码需要超过三层的缩进,那么你把⼀切都搞砸了,你应该修复你的程序。
简⽽⾔之,⼋个字符宽度的缩进让代码更容易阅读,并且额外的好处就是提醒你,不要在⼀个函数⾥写太多层的嵌套逻辑。
请记住这个警⽰。
switch语句的缩进⽅式是让case与switch对齐:switch (suffix) {case 'G':case 'g':mem <<= 30;break;case 'M':case 'm':mem <<= 20;break;case 'K':case 'k':mem <<= 10;/* fall through */default:break;}不要在单独⼀⾏⾥写多个语句,除⾮你想⼲什么不为⼈知的事:if (condition) do_this;do_something_everytime;对了,不要把多个赋值语句放在同⼀⾏,内核的代码风格是⼗分简洁的,请尽量避免使⽤复杂的表达式。
除了在注释、⽂档和Kconfig中,永远不要使⽤空格作为缩进,上⾯的例⼦是故意犯的错误。
找⼀个像样的编辑器,不要在⾏末留有空格。
2 换⾏规范代码风格的⽬的是提⾼代码的可读性和维护性。
单⾏的宽度限制为⼋⼗列,这是强烈推荐的设置。
Linux操作系统内核编译详解
内核,是一个操作系统的核心。
它负责管理系统的进程、内存、设备驱动程序、文件和网络系统,决定着系统的性能和稳定性。
Linux的一个重要的特点就是其源代码的公开性,所有的内核源程序都可以在/usr/src/linux下找到,大部分应用软件也都是遵循GPL而设计的,你都可以获取相应的源程序代码。
全世界任何一个软件工程师都可以将自己认为优秀的代码加入到其中,由此引发的一个明显的好处就是Linux修补漏洞的快速以及对最新软件技术的利用。
而Linux的内核则是这些特点的最直接的代表。
想象一下,拥有了内核的源程序对你来说意味着什么?首先,我们可以了解系统是如何工作的。
通过通读源代码,我们就可以了解系统的工作原理,这在Windows下简直是天方夜谭。
其次,我们可以针对自己的情况,量体裁衣,定制适合自己的系统,这样就需要重新编译内核。
在Windows下是什么情况呢?相信很多人都被越来越庞大的Windows整得莫名其妙过。
再次,我们可以对内核进行修改,以符合自己的需要。
这意味着什么?没错,相当于自己开发了一个操作系统,但是大部分的工作已经做好了,你所要做的就是要增加并实现自己需要的功能。
在Windows下,除非你是微软的核心技术人员,否则就不用痴心妄想了。
内核版本号由于Linux的源程序是完全公开的,任何人只要遵循GPL,就可以对内核加以修改并发布给他人使用。
Linux的开发采用的是集市模型(bazaar,与cathedral--教堂模型--对应),为了确保这些无序的开发过程能够有序地进行,Linux采用了双树系统。
一个树是稳定树(stable tree),另一个树是非稳定树(unstable tree)或者开发树(development tree)。
一些新特性、实验性改进等都将首先在开发树中进行。
如果在开发树中所做的改进也可以应用于稳定树,那么在开发树中经过测试以后,在稳定树中将进行相同的改进。
一旦开发树经过了足够的发展,开发树就会成为新的稳定树。
linux 的编码格式
linux 的编码格式【原创版】目录1.Linux 编码格式简介2.Linux 编码格式的发展历程3.Linux 编码格式的主要种类4.Linux 编码格式的应用实例5.Linux 编码格式的发展趋势正文【1.Linux 编码格式简介】Linux 编码格式是指在 Linux 操作系统中使用的字符编码方式。
由于 Linux 系统是一个多语言、多文化的操作系统,因此其编码格式也呈现出多样化的特点。
Linux 编码格式主要包括 UTF-8、GBK、GB2312 等,这些编码格式能够涵盖世界上大部分语言和字符。
【2.Linux 编码格式的发展历程】Linux 编码格式的发展经历了多个阶段。
最初,Linux 系统主要使用ASCII 编码,这种编码方式只能表示 128 个字符。
随着计算机的发展和信息交流的需求,Linux 系统开始采用更多的字符编码方式,比如ISO-8859-1,这种编码方式可以表示 256 个字符。
然而,这些编码方式仍然不能满足世界上所有语言和字符的需求。
因此,在 90 年代末,UTF-8 编码格式开始被广泛采用。
UTF-8 编码可以表示世界上所有语言和字符,并且具有字节顺序无关、可变长度等优点。
【3.Linux 编码格式的主要种类】Linux 编码格式主要包括 UTF-8、GBK、GB2312 等。
其中,UTF-8 编码是目前最常用的编码方式,它可以表示任何语言和字符。
GBK 和 GB2312 编码则是针对中文设计的编码方式,它们可以表示简体中文和繁体中文。
【4.Linux 编码格式的应用实例】在 Linux 系统中,编码格式的应用非常广泛。
比如,在编辑文本文件时,我们需要选择正确的编码格式来保存文件,以便于其他系统或程序能够正确地读取文件。
此外,在网络传输中,编码格式也起着重要的作用。
例如,在网页开发中,我们需要使用 UTF-8 编码来保证网页能够在各种设备和操作系统上正确显示。
【5.Linux 编码格式的发展趋势】随着计算机技术的发展和信息交流的加快,Linux 编码格式的发展趋势呈现出多元化和标准化的特点。
linux 的编码格式
linux 的编码格式摘要:1.Linux 的编码格式简介2.Linux 中常用的编码格式3.Linux 编码格式设置方法4.编码格式对Linux 系统的影响5.总结正文:Linux 的编码格式--------------------Linux 是一种开源的操作系统,由于其跨平台的特点,被广泛应用于服务器、嵌入式设备等多个领域。
在Linux 系统中,编码格式是用来表示文本的方式,不同的编码格式会影响到文本的显示、存储和传输。
本文将对Linux 的编码格式进行详细介绍。
Linux 中常用的编码格式------------------------在Linux 系统中,常用的编码格式有以下几种:1.ASCII 编码:ASCII(American Standard Code for Information Interchange,美国信息交换标准代码)是最早的编码格式,可以表示128 个字符,包括数字、字母和一些符号。
2.ISO-8859-1 编码:也称为Latin-1 编码,是ISO-8859 系列编码的一部分,可以表示256 个字符,包括西欧语言的基本字符和一些符号。
3.UTF-8 编码:UTF-8(Universal Character Set Transformation Format 8)是一种通用的编码格式,可以表示世界上几乎所有的字符。
UTF-8 编码采用可变长度的编码方式,具有很好的兼容性和可扩展性。
4.UTF-16 编码:UTF-16 是Unicode 字符集的一种编码方式,采用16 位编码,可以表示Unicode 字符集中的所有字符。
5.UTF-32 编码:UTF-32 是Unicode 字符集的另一种编码方式,采用32 位编码,可以表示Unicode 字符集中的所有字符。
Linux 编码格式设置方法----------------------在Linux 系统中,可以通过以下方法设置编码格式:1.文件编码:在创建或编辑文件时,可以使用文本编辑器(如vim、gedit 等)设置文件的编码格式。
linux内核版本编号规则
linux内核版本编号规则Linux内核版本编号规则Linux内核作为开源操作系统的核心,其版本编号规则是一个非常重要的内容。
正确理解和应用内核版本编号规则,对于操作系统的开发、维护和升级都具有重要意义。
本文将从不同的角度解读Linux内核版本编号规则,并探讨其中的含义和作用。
一、版本编号规则的基本原则Linux内核版本编号遵循的基本原则是"主版本号.次版本号.修订版本号"的格式。
其中,主版本号表示内核的重大更新,次版本号表示功能的增加或改进,修订版本号表示错误修复。
内核版本号中的各个部分都有特定的含义和作用,下面将对其进行详细解释。
1. 主版本号主版本号是内核版本编号中的第一个数字,它表示内核的重大更新。
通常情况下,主版本号的增加意味着内核发生了较大的改变,可能引入了新的功能、架构或者重要的优化。
主版本号的增加可能导致旧有的应用无法兼容,需要进行相应的适配和更新。
2. 次版本号次版本号是内核版本编号中的第二个数字,它表示功能的增加或改进。
当内核的功能得到了扩展或者改进时,次版本号会增加。
次版本号的增加通常不会影响应用的兼容性,但是可能需要重新编译和部署应用程序。
3. 修订版本号修订版本号是内核版本编号中的第三个数字,它表示错误修复。
当内核中发现了错误或者漏洞时,修订版本号会增加。
修订版本号的增加通常不会引入新的功能或者改变现有功能,只会修复已知的问题。
二、版本编号规则的实际应用Linux内核版本编号规则在实际应用中有着重要的意义。
通过观察内核版本号的变化,我们可以了解到内核的更新情况、功能改进和错误修复等信息。
同时,版本编号规则也为开发者和用户提供了一些有用的参考。
1. 版本号的递增关系根据版本编号规则,我们可以得出以下结论:- 主版本号的增加意味着内核发生了较大的改变,可能导致旧有的应用无法兼容。
- 次版本号的增加表示内核功能得到了扩展或者改进,不会影响应用的兼容性。
- 修订版本号的增加表示内核中发现了错误或者漏洞,需要进行相应的修复。
Linux内核编码风格(译文)
(c) when you use sparse to literally create a _new_ type for type-checking. (d) 在某种特殊情况下,和标准 C99 类型相同的类型。 虽然让眼睛和头脑来适应类似“uint32_t”一样的标准类型几乎不需要花时间,可还是 有些人拒绝接受。 因此, “u8/u16/u32/u64”类型和它们的有符号类型,可以说是 Linux 的事实标准,是可 以使用的,但并不做强制要求。 在修改代码时,如果该代码中已经选择了某个类型集,那么应该遵循现有规则。 (e) 可以在用户空间安全使用的类型。 在某些用户空间可见的结构体里, 我们不能要求 C99 类型, 并且不能用上面提到的 “u32” 类型。因此,我们在和用户空间共享的所有结构体中使用__u32 或者是类似的类型。 可能还有其他情况也会用到 typedef,不过基本的规则是永远不要使用 typedef,除非可 以明确的应用上述规则中的一个。 第六节:函数 函数应该短小精悍,并且只实现一个功能。它们应该一屏或者两屏显示完(我们都知道 ISO/ANSI 屏幕大小是 80x24) ,只实现一个功能,并把它做好。 一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。 所以, 如果你有这样一 个函数:只有一个 switch 语句,但有很多个不同的 case 分支,每个分支里面只需要做很小 的事情。这样的函数尽管很长,但也是可以接受的。 不过, 如果你有一个复杂的函数, 而且你怀疑一个天分不是很高的高中一年级学生甚至 可能搞不清楚这个函数的功能,你应该更严格的遵守最大限制。 进行函数拆分,并为之取个具有描述性的名字(如果你觉得其对性能要求严格的话,你 可以要求编译器将它们内联展开,它往往会比你更好的完成任务。 ) 函数另外一个衡量标准是局部变量的数量。通常来说,不应超过 5-10 个,否则这个函 数就有问题了。需要重新考虑一下,把它分拆成更小的函数。这是为什么呢?人的大脑一般 可以轻松的同时跟踪 7 个不同的事物,如果再多的话,就会糊涂了。即便你聪颖过人,也可 能会记不清你 2 个星期前做过的事情。 在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的 EXPORT*宏应 该紧贴在它的结束大括号之下。比如: int system_is_up(void) { return system_state == SYSTEM_RUNNING; } EXPORT_SYMBOL(system_is_up); 在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,但在 Linux 里这是首选的做法,因为这样可以很简单的给读者提供更多的有价值的信息。 第七节 集中函数出口
linux 内核编译各个选项的含义
linux 内核编译各个选项的含义linux内核编译各个选项的含义codematurityleveloptions代码成熟度选项表明尚在研发中或尚未顺利完成的代码与驱动.除非你就是测试人员或者开发者,否则切勿挑选generalsetup常规设置localversion-appendtokernelrelease在内核版本后面加上自定义的版本字符串(小于64字符),可以用\-a\命令看到automaticallyappendversioninformationtotheversionstring自动在版本字符串后面添加版本信息,编译时需要有perl以及git仓库支持supportforpagingofanonymousmemory(swap)使用交换分区或者交换文件来做为虚拟内存systemvipcsystemv进程间通信(ipc)积极支持,许多程序须要这个功能.克雷姆斯兰县,除非你晓得自己在搞什么ipcnamespacesipc命名空间支持,不确定可以不选posixmessagequeuesposix消息队列,这就是posixipc中的一部分bsdprocessaccounting将进程的统计信息写入文件的用户级系统调用,主要包括进程的创建时间/创建者/内存占用等信息bsdprocessaccountingversion3fileformat使用新的第三版文件格式,可以包含每个进程的pid和其父进程的pid,但是不兼容老版本的文件格式exporttask/processstatisticsthroughnetlink通过netlink接口向用户空间导出任务/进程的统计信息,与bsdprocessaccounting 的不同之处在于这些统计信息在整个任务/进程生存期都是可用的enableper-taskdelayaccounting在统计信息中包含进程等候系统资源(cpu,io同步,内存交换等)所花费的时间utsnamespacesuts名字空间积极支持,不确认可以说实话auditingsupport审计支持,某些内核模块(例如selinux)需要它,只有同时选择其子项才能对系统调用进行审计enablesystem-callauditingsupport支持对系统调用的审计kernel.configsupport把内核的布局信息编程入内核中,以后可以通过scripts/extract-ikconfig脚本去抽取这些信息enableaccessto.configthrough/proc/config.gz允许通过/proc/config.gz访问内核的配置信息cpusetsupport只有所含大量cpu(大于16个)的smp系统或numa(非一致内存出访)系统才须要它kernel->userspacerelaysupport(formerlyrelayfs)在某些文件系统上(比如说debugfs)提供更多从内核空间向用户空间传达大量数据的USBinitramfssourcefile(s)initrd已经被initramfs取代,如果你不明白这是什么意思,请保持空白编程时优化内核尺寸(采用\而不是\参数编程),有时可以产生错误的二进制代码enableextendedaccountingovertaskstats搜集额外的进程统计数据信息并通过taskstatsUSB发送到用户空间configurestandardkernelfeatures(forsmallsystems)配置标准的内核特性(为小型系统)enable16-bituidsystemcalls容许对uid系统调用展开过时的16-bit外包装sysctlsyscallsupport不需要重启就能修改内核的某些参数和变量,如果你也选择了支持/proc,将能从/proc/sys存取可以影响内核行为的参数或变量loadallsymbolsfordebugging/kksymoops装载所有的调试符号表信息,只供调试时挑选includeallsymbolsinkallsyms在kallsyms中包含内核知道的所有符号,内核将会增大300kdoanextrakallsymspass除非你在kallsyms中辨认出了bug并须要报告这个bug才关上该选项supportforhot-pluggabledevices支持热插拔设备,如usb与pc卡等,udev也需要它enablesupportforprintk容许内核向终端列印字符信息,在须要确诊内核为什么无法运转时挑选bug()support显示故障和失败条件(bug和warn),禁用它将可能导致隐含的错误被忽略enableelfcoredumps内存格式化积极支持,可以协助调试elf格式的程序enablefull-sizeddatastructuresforcore在内核中使用全尺寸的数据结构.禁用它将使得某些内核的数据结构减小以节约内存,但是将会降低性能enablefutexsupport快速用户空间互斥体可以使线程串行化以避免竞态条件,也提高了响应速度.禁用它将导致内核不能正确的运行基于glibc的程序enableeventpollsupport积极支持事件轮循的系统调用usefullshmemfilesystem完全使用shmem来代替ramfs.shmem是基于共享内存的文件系统(可能用到swap),在启用tmpfs后可以挂载为tmpfs供用户空间使用,它比简单的ramfs先进许多usefullslaballocator采用slab全然替代slob展开内存分配,slab就是一种杰出的内存分配管理器,所推荐采用enablevmeventcountersfor/proc/vmstat容许在/proc/vmstat中涵盖虚拟内存事件记数器loadablemodulesupport可加载模块支持enableloadablemodulesupport打开可加载模块支持,如果打开它则必须通过\把内核模块安装在/lib/modules/中moduleunloading容许装载已经读取的模块forcedmoduleunloading允许强制卸载正在使用中的模块(比较危险)moduleversioningsupport容许采用其他内核版本的模块(可能会出来问题)sourcechecksumforallmodules为所有的模块校验源码,如果你不是自己编写内核模块就不需要它automatickernelmoduleloading使内核通过运转modprobe去自动读取所须要的模块,比如说可以自动化解模块的倚赖关系blocklayer块设备层enabletheblocklayer块设备支持,使用硬盘/usb/scsi设备者必选supportforlargeblockdevices仅在采用大于2tb的块设备时须要supportfortracingblockioactions块队列io跟踪支持,它允许用户查看在一个块设备队列上发生的所有事件,可以通过blktrace程序获得磁盘当前的详细统计数据supportforlargesinglefiles仅在可能将采用大于2tb的文件时须要ioschedulersio调度器anticipatoryi/oscheduler假设一个块设备只有一个物理查找磁头(例如一个单独的sata硬盘),将多个随机的小写入流合并成一个大写入流,用写入延时换取最大的写入吞吐量.适用于大多数环境,特别是写入较多的环境(比如文件服务器)deadlinei/oscheduler采用轮询的调度器,简约小巧,提供更多了最轻的加载延后和尚尽如人意的吞吐量,特别适合于加载较多的环境(比如说数据库)cfqi/oscheduler使用qos策略为所有任务分配等量的带宽,避免进程被饿死并实现了较低的延迟,可以认为是上述两种调度器的折中.适用于有大量进程的多用户系统defaulti/oscheduler默认io调度器。
Linux内核源代码分析
Linux内核源代码的组成
核心模块
– 核心模块代码部分布在内核中,部分位 于modules包中。核心代码位于 kernel/modules.c且其数据结构与核心后 台进程kerneld消息位于 include/linux/module.h和 include/linux/kerneld.h目录中。必要时 需查阅inlude/linux/elf.h中的ELF文件格 式。
– 利用自由软件让个人计算机带十几个硬 盘实现阵列技术,及其亚微米超大规模 集成电路CAD系统,可直接输出生产线 控制数据等。
– Linux内核的许多面向通信的底层代码对 开发我国自己的信息安全产品极有参考 价值。
分析Linux内核的意义
开发高水平软件
– 目前Linux的源代码中包含了世界各地几 百名计算机高手的作品,分析这些源代 码对于我们掌握核心技术会起到事半功 倍的作用,尤其是各种驱动程序的编写, 对于我们把软硬件结合起来发展民族信 息产业至关重要。
Linux内核源代码的组成
核心
– 大多数通用代码位于kernel目录下,而处理器相 关代码被放在arch/kernel中,调度管理程序位 于kernel/sched.c ,fork代码位于kernel/fork.c。 底层部分处理及中断处理的代码位于 include/linux/interrupt.h里。在/linux/sched.h中 可以找到task_struct的描述。
– Windows下的一个阅读源代码的工具:Source Insight。该软件可从下载
– Linux下一个阅读源代码的工具是LXR
网络
– 网络代码位于net目录而大多数包含文件位于 include/net中,BSD套接字代码位于socket.c中。 IPv4的INET套接字代码位于net/ipv4/af_inet.c中。 通用协议支撑代码(包括sk_buff处理过程)位 于net/core中,同时TCP/IP网络代码位于 net/ipv4中。网络设备驱动位于drivers/net中。
linux操作系统内核版表达方式
Linux操作系统内核源代码的表达方式Linux操作系统内核源代码的表达方式是指内核代码中所使用的语法和结构。
它决定了内核代码的可读性、可维护性和可移植性。
内核源代码的表达方式主要包括以下几个方面:语法:Linux内核源代码使用C语言编写。
C语言是一种广泛使用的通用编程语言,具有丰富的库和工具支持,并且很容易移植到不同的平台上。
结构:Linux内核源代码由许多相互关联的文件组成,这些文件包含了内核的各种功能和模块。
内核源代码的结构通常是分层的,每一层都包含了不同的功能。
命名约定:Linux内核源代码使用了严格的命名约定,这使得内核代码更容易阅读和维护。
例如,内核中的函数通常以“sys_”或“do_”开头,而结构体通常以“struct_”开头。
注释:Linux内核源代码中包含了大量的注释,这些注释解释了代码的功能和用法。
注释对于理解内核代码非常有用,尤其是对于新内核开发者来说。
Linux内核源代码的表达方式的特点Linux内核源代码的表达方式具有以下几个特点:简洁:Linux内核源代码非常简洁,代码中没有多余的注释和代码段。
这种简洁性使得内核代码更容易阅读和维护。
模块化:Linux内核源代码是模块化的,内核中的各个模块可以独立编译和加载。
这种模块化设计使得内核更容易扩展和维护。
可移植性:Linux内核源代码具有很强的可移植性,它可以移植到不同的硬件平台上。
这种可移植性使得Linux内核成为世界上最受欢迎的操作系统之一。
Linux内核源代码的表达方式的优点Linux内核源代码的表达方式具有以下几个优点:可读性:Linux内核源代码非常可读,代码中的注释和命名约定使得内核代码很容易理解。
这种可读性对于内核开发者来说非常重要,它可以帮助开发者快速理解和修改内核代码。
可维护性:Linux内核源代码也非常可维护,代码中的模块化设计使得内核更容易扩展和维护。
这种可维护性对于内核的长期发展非常重要,它可以确保内核能够不断更新和改进。
Linux内核编码风格
Linux内核编码风格 像其他⼤型软件⼀样,Linux制订了⼀套编码风格,对代码的格式、风格和布局做出了规定。
我写这篇的⽬的也就是希望⼤家能够从中借鉴,有利于⼤家提⾼编程效率。
像Linux内核这样⼤型软件中,涉及许许多多的开发者,故它的编码风格也很有参考价值。
1、左括号紧跟在语句的最后,与语句在相同的⼀⾏。
⽽右括号要另起⼀⾏,作为该⾏的第⼀个字符。
2、如果接下来的部分是相同语句的⼀部分,那么右括号就不单独占⼀⾏。
3、还有 4、函数采⽤以下的书写⽅式: 5、最后不需要⼀定使⽤括号的语句可以忽略它: 要尽可能地保证代码长度不超过80个字符,如果代码⾏超过80应该折到下⼀⾏。
将参数分⾏输⼊,在开头简单地加⼊两个标准tab: 名称中不允许使⽤混合的⼤⼩写字符。
局部变量如果能够清楚地表明它的⽤途,那么选取idx甚⾄是i这样的名称都是可⾏的。
⽽像theLoopIndex这样冗长反复的名字不在接受之列。
——匈⽛利命名法(在变量名称中加⼊变量的类别)危害极⼤。
函数 根据经验函数的代码长度不应该超过两屏,局部变量不应该超过⼗个。
1、⼀个函数应该功能单⼀并且实现精准。
2、将⼀个函数分解成⼀些更短⼩的函数的组合不会带来危害。
——如果你担⼼函数调⽤导致的开销,可以使⽤inline关键字。
⼀般情况下,注释的⽬的是描述你的代码要做什么和为什么要做,⽽不是具体通过什么⽅式实现的。
怎么实现应该由代码本⾝展现。
注释不应该包含谁写了那个函数,修改⽇期和其他那些琐碎⽽⽆实际意义的内容。
这些信息应该集中在⽂件最开头地⽅。
内核中⼀条注释看起来如下: 重要信息常常以“XXX:”开头,⽽bug通常以“FIXME"开头,就像:总结 希望这篇博客对⼤家有所帮助!更详尽的内容,请看"Linux 内核代码规范原⽂"Linus 内部代码规范原⽂1 Linux kernel coding style23 This is a short document describing the preferred coding style for the4 linux kernel. Coding style is very personal, and I won't _force_ my5 views on anybody, but this is what goes for anything that I have to be6 able to maintain, and I'd prefer it for most other things too. Please7 at least consider the points made here.89 First off, I'd suggest printing out a copy of the GNU coding standards,10 and NOT read it. Burn them, it's a great symbolic gesture.1112 Anyway, here goes:131415 Chapter 1: Indentation1617 Tabs are 8 characters, and thus indentations are also 8 characters.18 There are heretic movements that try to make indentations 4 (or even 2!)19 characters deep, and that is akin to trying to define the value of PI to20 be 3.2122 Rationale: The whole idea behind indentation is to clearly define where23 a block of control starts and ends. Especially when you've been looking24 at your screen for20 straight hours, you'll find it a lot easier to see25 how the indentation works if you have large indentations.2627 Now, some people will claim that having 8-character indentations makes28 the code move too far to the right, and makes it hard to read on a2980-character terminal screen. The answer to that is that if you need30 more than 3 levels of indentation, you're screwed anyway, and should fix31 your program.3233 In short, 8-char indents make things easier to read, and have the added34 benefit of warning you when you're nesting your functions too deep.35 Heed that warning.3637 The preferred way to ease multiple indentation levels in a switch statement is38 to align the "switch" and its subordinate "case" labels in the same column39 instead of "double-indenting" the "case" labels. E.g.:4041switch (suffix) {42case'G':43case'g':44 mem <<= 30;45break;46case'M':47case'm':48 mem <<= 20;49break;51case'k':52 mem <<= 10;53/* fall through */54default:55break;56 }575859 Don't put multiple statements on a single line unless you have60 something to hide:6162if (condition) do_this;63 do_something_everytime;6465 Don't put multiple assignments on a single line either. Kernel coding style66is super simple. Avoid tricky expressions.6768 Outside of comments, documentation and except in Kconfig, spaces are never69 used for indentation, and the above example is deliberately broken.7071 Get a decent editor and don't leave whitespace at the end of lines.727374 Chapter 2: Breaking long lines and strings7576 Coding style is all about readability and maintainability using commonly77 available tools.7879 The limit on the length of lines is80 columns and this is a strongly80 preferred limit.8182 Statements longer than 80 columns will be broken into sensible chunks, unless83 exceeding 80 columns significantly increases readability and does not hide84 information. Descendants are always substantially shorter than the parent and85 are placed substantially to the right. The same applies to function headers86 with a long argument list. However, never break user-visible strings such as87 printk messages, because that breaks the ability to grep for them.888990 Chapter 3: Placing Braces and Spaces9192 The other issue that always comes up in C styling is the placement of93 braces. Unlike the indent size, there are few technical reasons to94 choose one placement strategy over the other, but the preferred way, as95 shown to us by the prophets Kernighan and Ritchie, is to put the opening96 brace last on the line, and put the closing brace first, thusly:9798if (x is true) {99 we do y100 }101102 This applies to all non-function statement blocks (if, switch, for,103while, do). E.g.:104105switch (action) {106case KOBJ_ADD:107return"add";108case KOBJ_REMOVE:109return"remove";110case KOBJ_CHANGE:111return"change";112default:113return NULL;114 }115116 However, there is one special case, namely functions: they have the117 opening brace at the beginning of the next line, thus:118119int function(int x)120 {121 body of function122 }123124 Heretic people all over the world have claimed that this inconsistency125is ... well ... inconsistent, but all right-thinking people know that126 (a) K&R are _right_ and (b) K&R are right. Besides, functions are127 special anyway (you can't nest them in C).128129 Note that the closing brace is empty on a line of its own, _except_ in130 the cases where it is followed by a continuation of the same statement,131 ie a "while"in a do-statement or an "else"in an if-statement, like132this:133135 body of do-loop136 } while (condition);137138 and139140if (x == y) {141 ..142 } else if (x > y) {143 ...144 } else {145 ....146 }147148 Rationale: K&R.149150 Also, note that this brace-placement also minimizes the number of empty151 (or almost empty) lines, without any loss of readability. Thus, as the152 supply of new-lines on your screen is not a renewable resource (think15325-line terminal screens here), you have more empty lines to put154 comments on.155156 Do not unnecessarily use braces where a single statement will do.157158if (condition)159 action();160161 and162163if (condition)164 do_this();165else166 do_that();167168 This does not apply if only one branch of a conditional statement is a single 169 statement; in the latter case use braces in both branches:170171if (condition) {172 do_this();173 do_that();174 } else {175 otherwise();176 }177178 3.1: Spaces179180 Linux kernel style for use of spaces depends (mostly) on181 function-versus-keyword usage. Use a space after (most) keywords. The 182 notable exceptions are sizeof, typeof, alignof, and __attribute__, which look 183 somewhat like functions (and are usually used with parentheses in Linux,184 although they are not required in the language, as in: "sizeof info" after 185"struct fileinfo info;"is declared).186187 So use a space after these keywords:188if, switch, case, for, do, while189 but not with sizeof, typeof, alignof, or __attribute__. E.g.,190 s = sizeof(struct file);191192 Do not add spaces around (inside) parenthesized expressions. This example is 193 *bad*:194195 s = sizeof( struct file );196197 When declaring pointer data or a function that returns a pointer type, the198 preferred use of '*'is adjacent to the data name or function name and not199 adjacent to the type name. Examples:200201char *linux_banner;202 unsigned long long memparse(char *ptr, char **retptr);203char *match_strdup(substring_t *s);204205 Use one space around (on each side of) most binary and ternary operators, 206 such as any of these:207208 = + - < > * / % | & ^ <= >= == != ? :209210 but no space after unary operators:211 & * + - ~ ! sizeof typeof alignof __attribute__ defined212213 no space before the postfix increment & decrement unary operators:214 ++ --215216 no space after the prefix increment & decrement unary operators:217 ++ --219 and no space around the '.' and "->" structure member operators.220221 Do not leave trailing whitespace at the ends of lines. Some editors with 222"smart" indentation will insert whitespace at the beginning of new lines as 223 appropriate, so you can start typing the next line of code right away.224 However, some such editors do not remove the whitespace if you end up not 225 putting a line of code there, such as if you leave a blank line. As a result, 226 you end up with lines containing trailing whitespace.227228 Git will warn you about patches that introduce trailing whitespace, and can 229 optionally strip the trailing whitespace for you; however, if applying a series 230 of patches, this may make later patches in the series fail by changing their 231 context lines.232233234 Chapter 4: Naming235236 C is a Spartan language, and so should your naming be. Unlike Modula-2 237 and Pascal programmers, C programmers do not use cute names like238 ThisVariableIsATemporaryCounter. A C programmer would call that239 variable "tmp", which is much easier to write, and not the least more240 difficult to understand.241242 HOWEVER, while mixed-case names are frowned upon, descriptive names for 243global variables are a must. To call a global function "foo"is a244 shooting offense.245246 GLOBAL variables (to be used only if you _really_ need them) need to247 have descriptive names, as do global functions. If you have a function248 that counts the number of active users, you should call that249"count_active_users()" or similar, you should _not_ call it "cntusr()".250251 Encoding the type of a function into the name (so-called Hungarian252 notation) is brain damaged - the compiler knows the types anyway and can 253 check those, and it only confuses the programmer. No wonder MicroSoft 254 makes buggy programs.255256 LOCAL variable names should be short, and to the point. If you have257 some random integer loop counter, it should probably be called "i".258 Calling it "loop_counter"is non-productive, if there is no chance of it259 being mis-understood. Similarly, "tmp" can be just about any type of260 variable that is used to hold a temporary value.261262 If you are afraid to mix up your local variable names, you have another263 problem, which is called the function-growth-hormone-imbalance syndrome. 264 See chapter 6 (Functions).265266267 Chapter 5: Typedefs268269 Please don't use things like "vps_t".270271 It's a _mistake_ to use typedef for structures and pointers. When you see a 272273 vps_t a;274275in the source, what does it mean?276277 In contrast, if it says278279struct virtual_container *a;280281 you can actually tell what "a"is.282283 Lots of people think that typedefs "help readability". Not so. They are284 useful only for:285286 (a) totally opaque objects (where the typedef is actively used to _hide_287 what the object is).288289 Example: "pte_t" etc. opaque objects that you can only access using290 the proper accessor functions.291292 NOTE! Opaqueness and "accessor functions" are not good in themselves. 293 The reason we have them for things like pte_t etc. is that there294 really is absolutely _zero_ portably accessible information there.295296 (b) Clear integer types, where the abstraction _helps_ avoid confusion297 whether it is"int" or "long".298299 u8/u16/u32 are perfectly fine typedefs, although they fit into300 category (d) better than here.301303"unsigned long", then there's no reason to do304305 typedef unsigned long myflags_t;306307 but if there is a clear reason for why it under certain circumstances308 might be an "unsigned int" and under other configurations might be 309"unsigned long", then by all means go ahead and use a typedef.310311 (c) when you use sparse to literally create a _new_ type for312 type-checking.313314 (d) New types which are identical to standard C99 types, in certain315 exceptional circumstances.316317 Although it would only take a short amount of time for the eyes and318 brain to become accustomed to the standard types like 'uint32_t',319 some people object to their use anyway.320321 Therefore, the Linux-specific 'u8/u16/u32/u64' types and their322 signed equivalents which are identical to standard types are323 permitted -- although they are not mandatory in new code of your324 own.325326 When editing existing code which already uses one or the other set327 of types, you should conform to the existing choices in that code.328329 (e) Types safe for use in userspace.330331 In certain structures which are visible to userspace, we cannot332 require C99 types and cannot use the 'u32' form above. Thus, we333 use __u32 and similar types in all structures which are shared334 with userspace.335336 Maybe there are other cases too, but the rule should basically be to NEVER 337 EVER use a typedef unless you can clearly match one of those rules.338339 In general, a pointer, or a struct that has elements that can reasonably340 be directly accessed should _never_ be a typedef.341342343 Chapter 6: Functions344345 Functions should be short and sweet, and do just one thing. They should346 fit on one or two screenfuls of text (the ISO/ANSI screen size is 80x24,347as we all know), and do one thing and do that well.348349 The maximum length of a function is inversely proportional to the350 complexity and indentation level of that function. So, if you have a351 conceptually simple function that is just one long (but simple)352case-statement, where you have to do lots of small things for a lot of353 different cases, it's OK to have a longer function.354355 However, if you have a complex function, and you suspect that a356 less-than-gifted first-year high-school student might not even357 understand what the function is all about, you should adhere to the358 maximum limits all the more closely. Use helper functions with359 descriptive names (you can ask the compiler to in-line them if you think360 it's performance-critical, and it will probably do a better job of it361 than you would have done).362363 Another measure of the function is the number of local variables. They364 shouldn't exceed 5-10, or you're doing something wrong. Re-think the365 function, and split it into smaller pieces. A human brain can366 generally easily keep track of about 7 different things, anything more367 and it gets confused. You know you're brilliant, but maybe you'd like368 to understand what you did 2 weeks from now.369370 In source files, separate functions with one blank line. If the function is371 exported, the EXPORT* macro for it should follow immediately after the closing 372 function brace line. E.g.:373374int system_is_up(void)375 {376return system_state == SYSTEM_RUNNING;377 }378 EXPORT_SYMBOL(system_is_up);379380 In function prototypes, include parameter names with their data types.381 Although this is not required by the C language, it is preferred in Linux382 because it is a simple way to add valuable information for the reader.383384385 Chapter 7: Centralized exiting of functions387 Albeit deprecated by some people, the equivalent of the goto statement is388 used frequently by compilers in form of the unconditional jump instruction.389390 The goto statement comes in handy when a function exits from multiple391 locations and some common work such as cleanup has to be done.392393 The rationale is:394395 - unconditional statements are easier to understand and follow396 - nesting is reduced397 - errors by not updating individual exit points when making398 modifications are prevented399 - saves the compiler work to optimize redundant code away ;)400401int fun(int a)402 {403int result = 0;404char *buffer = kmalloc(SIZE);405406if (buffer == NULL)407return -ENOMEM;408409if (condition1) {410while (loop1) {411 ...412 }413 result = 1;414goto out;415 }416 ...417out:418 kfree(buffer);419return result;420 }421422 Chapter 8: Commenting423424 Comments are good, but there is also a danger of over-commenting. NEVER 425try to explain HOW your code works in a comment: it's much better to426 write the code so that the _working_ is obvious, and it's a waste of427 time to explain badly written code.428429 Generally, you want your comments to tell WHAT your code does, not HOW. 430 Also, try to avoid putting comments inside a function body: if the431 function is so complex that you need to separately comment parts of it,432 you should probably go back to chapter 6for a while. You can make433 small comments to note or warn about something particularly clever (or434 ugly), but try to avoid excess. Instead, put the comments at the head435 of the function, telling people what it does, and possibly WHY it does436 it.437438 When commenting the kernel API functions, please use the kernel-doc format. 439 See the files Documentation/kernel-doc-nano-HOWTO.txt and scripts/kernel-doc 440for details.441442 Linux style for comments is the C89 "/* ... */" style.443 Don't use C99-style "// ..." comments.444445 The preferred style for long (multi-line) comments is:446447/*448 * This is the preferred style for multi-line449 * comments in the Linux kernel source code.450 * Please use it consistently.451 *452 * Description: A column of asterisks on the left side,453 * with beginning and ending almost-blank lines.454*/455456 For files in net/ and drivers/net/ the preferred style for long (multi-line)457 comments is a little different.458459/* The preferred comment style for files in net/ and drivers/net460 * looks like this.461 *462 * It is nearly the same as the generally preferred comment style,463 * but there is no initial almost-blank line.464*/465466 It's also important to comment data, whether they are basic types or derived 467 types. To this end, use just one data declaration per line (no commas for468 multiple data declarations). This leaves you room for a small comment on each 469 item, explaining its use.472 Chapter 9: You've made a mess of it473474 That's OK, we all do. You've probably been told by your long-time Unix 475 user helper that "GNU emacs" automatically formats the C sources for476 you, and you've noticed that yes, it does do that, but the defaults it477 uses are less than desirable (in fact, they are worse than random478 typing - an infinite number of monkeys typing into GNU emacs would never 479 make a good program).480481 So, you can either get rid of GNU emacs, or change it to use saner482 values. To do the latter, you can stick the following in your .emacs file: 483484 (defun c-lineup-arglist-tabs-only (ignored)485"Line up argument lists by tabs, not spaces"486 (let* ((anchor (c-langelem-pos c-syntactic-element))487 (column (c-langelem-2nd-pos c-syntactic-element))488 (offset (- (1+ column) anchor))489 (steps (floor offset c-basic-offset)))490 (* (max steps 1)491 c-basic-offset)))492493 (add-hook 'c-mode-common-hook494 (lambda ()495 ;; Add kernel style496 (c-add-style497"linux-tabs-only"498'("linux" (c-offsets-alist499 (arglist-cont-nonempty500 c-lineup-gcc-asm-reg501 c-lineup-arglist-tabs-only))))))502503 (add-hook 'c-mode-hook504 (lambda ()505 (let ((filename (buffer-file-name)))506 ;; Enable kernel mode for the appropriate files507 (when (and filename508 (string-match (expand-file-name "~/src/linux-trees")509 filename))510 (setq indent-tabs-mode t)511 (c-set-style "linux-tabs-only")))))512513 This will make emacs go better with the kernel coding style for C514 files below ~/src/linux-trees.515516 But even if you fail in getting emacs to do sane formatting, not517 everything is lost: use "indent".518519 Now, again, GNU indent has the same brain-dead settings that GNU emacs 520 has, which is why you need to give it a few command line options.521 However, that's not too bad, because even the makers of GNU indent522 recognize the authority of K&R (the GNU people aren't evil, they are523 just severely misguided in this matter), so you just give indent the524 options "-kr -i8" (stands for"K&R, 8 character indents"), or use 525"scripts/Lindent", which indents in the latest style.526527"indent" has a lot of options, and especially when it comes to comment 528 re-formatting you may want to take a look at the man page. But529 remember: "indent"is not a fix for bad programming.530531532 Chapter 10: Kconfig configuration files533534 For all of the Kconfig* configuration files throughout the source tree,535 the indentation is somewhat different. Lines under a "config" definition536 are indented with one tab, while help text is indented an additional two537 spaces. Example:538539 config AUDIT540bool"Auditing support"541 depends on NET542 help543 Enable auditing infrastructure that can be used with another544 kernel subsystem, such as SELinux (which requires this for545 logging of avc messages output). Does not do system-call546 auditing without CONFIG_AUDITSYSCALL.547548 Features that might still be considered unstable should be defined as549 dependent on "EXPERIMENTAL":550551 config SLUB552 depends on EXPERIMENTAL && !ARCH_USES_SLAB_PAGE_STRUCT 553bool"SLUB (Unqueued Allocator)"556while seriously dangerous features (such as write support for certain557 filesystems) should advertise this prominently in their prompt string:558559 config ADFS_FS_RW560bool"ADFS write support (DANGEROUS)"561 depends on ADFS_FS562 ...563564 For full documentation on the configuration files, see the file565 Documentation/kbuild/kconfig-language.txt.566567568 Chapter 11: Data structures569570 Data structures that have visibility outside the single-threaded571 environment they are created and destroyed in should always have572 reference counts. In the kernel, garbage collection doesn't exist (and573 outside the kernel garbage collection is slow and inefficient), which574 means that you absolutely _have_ to reference count all your uses.575576 Reference counting means that you can avoid locking, and allows multiple 577 users to have access to the data structure in parallel - and not having578 to worry about the structure suddenly going away from under them just579 because they slept or did something else for a while.580581 Note that locking is _not_ a replacement for reference counting.582 Locking is used to keep data structures coherent, while reference583 counting is a memory management technique. Usually both are needed, and 584 they are not to be confused with each other.585586 Many data structures can indeed have two levels of reference counting,587 when there are users of different "classes". The subclass count counts588 the number of subclass users, and decrements the global count just once 589 when the subclass count goes to zero.590591 Examples of this kind of "multi-level-reference-counting" can be found in592 memory management ("struct mm_struct": mm_users and mm_count), and in 593 filesystem code ("struct super_block": s_count and s_active).594595 Remember: if another thread can find your data structure, and you don't596 have a reference count on it, you almost certainly have a bug.597598599 Chapter 12: Macros, Enums and RTL600601 Names of macros defining constants and labels in enums are capitalized. 602603#define CONSTANT 0x12345604605 Enums are preferred when defining several related constants.606607 CAPITALIZED macro names are appreciated but macros resembling functions 608 may be named in lower case.609610 Generally, inline functions are preferable to macros resembling functions. 611612 Macros with multiple statements should be enclosed in a do - while block: 613614#define macrofun(a, b, c) \615do { \616if (a == 5) \617 do_this(b, c); \618 } while (0)619620 Things to avoid when using macros:6216221) macros that affect control flow:623624#define FOO(x) \625do { \626if (blah(x) < 0) \627return -EBUGGERED; \628 } while(0)629630is a _very_ bad idea. It looks like a function call but exits the "calling"631 function; don't break the internal parsers of those who will read the code.6326332) macros that depend on having a local variable with a magic name:634635#define FOO(val) bar(index, val)636637 might look like a good thing, but it's confusing as hell when one reads the6403) macros with arguments that are used as l-values: FOO(x) = y; will641 bite you if somebody e.g. turns FOO into an inline function.6426434) forgetting about precedence: macros defining constants using expressions644 must enclose the expression in parentheses. Beware of similar issues with645 macros using parameters.646647#define CONSTANT 0x4000648#define CONSTEXP (CONSTANT | 3)649650 The cpp manual deals with macros exhaustively. The gcc internals manual also 651 covers RTL which is used frequently with assembly language in the kernel.652653654 Chapter 13: Printing kernel messages655656 Kernel developers like to be seen as literate. Do mind the spelling657 of kernel messages to make a good impression. Do not use crippled658 words like "dont"; use "do not" or "don't" instead. Make the messages659 concise, clear, and unambiguous.660661 Kernel messages do not have to be terminated with a period.662663 Printing numbers in parentheses (%d) adds no value and should be avoided.664665 There are a number of driver model diagnostic macros in <linux/device.h>666 which you should use to make sure messages are matched to the right device 667 and driver, and are tagged with the right level: dev_err(), dev_warn(),668 dev_info(), and so forth. For messages that aren't associated with a669 particular device, <linux/printk.h> defines pr_debug() and pr_info().670671 Coming up with good debugging messages can be quite a challenge; and once 672 you have them, they can be a huge help for remote troubleshooting. Such673 messages should be compiled out when the DEBUG symbol is not defined (that 674is, by default they are not included). When you use dev_dbg() or pr_debug(),675 that's automatic. Many subsystems have Kconfig options to turn on -DDEBUG. 676 A related convention uses VERBOSE_DEBUG to add dev_vdbg() messages to the 677 ones already enabled by DEBUG.678679680 Chapter 14: Allocating memory681682 The kernel provides the following general purpose memory allocators:683 kmalloc(), kzalloc(), kmalloc_array(), kcalloc(), vmalloc(), and684 vzalloc(). Please refer to the API documentation for further information685 about them.686687 The preferred form for passing a size of a struct is the following:688689 p = kmalloc(sizeof(*p), ...);690691 The alternative form where struct name is spelled out hurts readability and692 introduces an opportunity for a bug when the pointer variable type is changed693 but the corresponding sizeof that is passed to a memory allocator is not.694695 Casting the return value which is a void pointer is redundant. The conversion696from void pointer to any other pointer type is guaranteed by the C programming 697 language.698699 The preferred form for allocating an array is the following:700701 p = kmalloc_array(n, sizeof(...), ...);702703 The preferred form for allocating a zeroed array is the following:704705 p = kcalloc(n, sizeof(...), ...);706707 Both forms check for overflow on the allocation size n * sizeof(...),708 and return NULL if that occurred.709710711 Chapter 15: The inline disease712713 There appears to be a common misperception that gcc has a magic "make me 714 faster" speedup option called "inline". While the use of inlines can be715 appropriate (for example as a means of replacing macros, see Chapter 12), it716 very often is not. Abundant use of the inline keyword leads to a much bigger717 kernel, which in turn slows the system as a whole down, due to a bigger718 icache footprint for the CPU and simply because there is less memory719 available for the pagecache. Just think about it; a pagecache miss causes a720 disk seek, which easily takes 5 milliseconds. There are a LOT of cpu cycles721 that can go into these 5 milliseconds.。
Linux内核--内核数据类型【转】
但是还有一个更好的方法:Linux 内核有一套宏定义来处理处理器字节序和特定字节序之间的转换。例如: u32 cpu_to_le32 (u32); u32 le32_to_cpu (u32); /*这些宏定义将一个CPU使用的值转换成一个无符号的32位小头数值,无论 CPU 是大端还是小端,也不管是不是32 位处理器。在没有转换 工作需要做时,返回未修改的值。*/
数据对齐
编写可移植代码而值得考虑的最后一个问题是如何访问未对齐的数据。存取不对齐的数据应当使用下列宏: #include <asm/unaligned.h> get_unaligned(ptr); put_unaligned(val, ptr); 这些宏是无类型的,并对各总数据项,不管是 1、2、4或 8 个字节,他们都有效,并且在所有内核版本中都有定义。
只要驱动使用了这种定制类型的函数但又不遵照约定编译器会发出警告这时使用wall编译器选项并小心去除所有的警告就可以确信代码的可移植性了
Linux内核 --内核数据类型【转】
将Linux 移植到新的体系结构时,开发者遇到的若干问题都与不正确的数据类型有关。坚持使用严格的数据类型和使用 -Wall -Wstrictprototypes 进行编译可能避免大部分的 bug。
linux 服务器 中文路径 编码规则
在Linux服务器上,中文路径的编码规则主要涉及到字符编码和文件系统。
以下是关于在Linux服务器上使用中文路径的一些重要注意事项:1. **字符编码**:- Linux系统通常使用UTF-8字符编码来处理文本数据,这也包括文件和目录名称。
- UTF-8是一种多字节编码,能够支持各种语言,包括中文。
- 确保你的终端和应用程序都使用UTF-8编码,以避免字符乱码问题。
2. **文件系统编码**:- 大多数Linux文件系统(如ext4、XFS等)支持UTF-8编码的文件和目录名称。
- 这意味着你可以创建和使用包含中文字符的文件和目录名称,只要操作系统和文件系统都正确配置了UTF-8编码。
3. **路径分隔符**:- 在Linux中,路径分隔符通常是斜杠(/),不像Windows中使用反斜杠(\)。
- 因此,一个典型的中文路径可能如下所示:`/home/用户/文档/中文文件夹/文件.txt`4. **注意文件名长度**:- 文件系统通常对文件名长度有一定的限制,这包括字符数和字节数。
不同文件系统的限制不同。
- 长文件名可能会导致问题,因此在创建中文文件名时要小心不要超出文件系统的限制。
5. **字符转义**:- 在命令行中,如果你需要在文件名中使用特殊字符或空格,可以使用字符转义或引号。
- 例如,如果你有一个文件名中包含空格的文件,可以使用反斜杠转义空格,或者将整个文件名用引号括起来:`文件\ 名字.txt` 或`"文件名字.txt"`总之,在Linux服务器上使用中文路径通常不是问题,前提是你正确设置字符编码,使用支持UTF-8的文件系统,避免超长文件名,以及在命令行中正确处理特殊字符和空格。
如果你在使用特定应用程序或脚本时遇到问题,请确保它们也正确支持中文路径。
Linux查看文件编码格式与文件编码转换
Linux 查看文件编码格式及文件编码转换如果你需要在 Linux 中操作 windows 下的文件,那么你可能会经常遇到文件编码转换的问题。
Windows中默认的文件格式是 GBK(gb2312),而 Linux 一般都是UTF-8。
下面介绍一下,在 Linux 中如何查看文件的编码及如何进展对文件进展编码转换。
查看文件编码在 Linux 中查看文件编码可以通过以下几种方式:1.在 Vim 中可以直接查看文件编码Shell 代码:setfileencoding即可显示文件编码格式。
如果你只是想查看其它编码格式的文件或者想解决用 Vim 查看文件乱码的问题,那么你可以在~/.vimrc文件中添加以下内容:Shell 代码setencoding=utf-8fileencodings=ucs-bom,utf-8,cp936这样,就可以让 vim 自动识别文件编码〔可以自动识别 UTF-8 或者 GBK编码的文件〕,其实就是依照 fileencodings 提供的编码列表尝试,如果没有找到适宜的编码,就用 latin-1(ASCII) 编码翻开。
2.enca( 如果你的系统中没有安装这个命令,可以用sudoyuminstall-yenca安装 ) 查看文件编码$encafilenamefilename:Universaltransformationformat8bits;UTF-8CRLFlineterminators需要说明一点的是, enca 对某些 GBK编码的文件识别的不是很好,识别时会出现:Unrecognizedencoding文件编码转换1.在 Vim 中直接进展转换文件编码 , 比方将一个文件转换成 utf-8 格式Shell 代码:setfileencoding=utf-82.enconv 转换文件编码,比方要将一个 GBK编码的文件转换成UTF-8 编码,操作如下enconv-Lzh_CN-xUTF-8filename3.iconv转换,iconv的命令格式如下:iconv-fencoding-tencodinginputfile比方将一个 UTF-8 编码的文件转换成GBK编码iconv-fGBK-tUTF-8file1-ofile2。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
(c) when you use sparse to literally create a _new_ type for type-checking. (d) 在某种特殊情况下,和标准 C99 类型相同的类型。 虽然让眼睛和头脑来适应类似“uint32_t”一样的标准类型几乎不需要花时间,可还是 有些人拒绝接受。 因此, “u8/u16/u32/u64”类型和它们的有符号类型,可以说是 Linux 的事实标准,是可 以使用的,但并不做强制要求。 在修改代码时,如果该代码中已经选择了某个类型集,那么应该遵循现有规则。 (e) 可以在用户空间安全使用的类型。 在某些用户空间可见的结构体里, 我们不能要求 C99 类型, 并且不能用上面提到的 “u32” 类型。因此,我们在和用户空间共享的所有结构体中使用__u32 或者是类似的类型。 可能还有其他情况也会用到 typedef,不过基本的规则是永远不要使用 typedef,除非可 以明确的应用上述规则中的一个。 第六节:函数 函数应该短小精悍,并且只实现一个功能。它们应该一屏或者两屏显示完(我们都知道 ISO/ANSI 屏幕大小是 80x24) ,只实现一个功能,并把它做好。 一个函数的最大长度是和该函数的复杂度和缩进级数成反比的。 所以, 如果你有这样一 个函数:只有一个 switch 语句,但有很多个不同的 case 分支,每个分支里面只需要做很小 的事情。这样的函数尽管很长,但也是可以接受的。 不过, 如果你有一个复杂的函数, 而且你怀疑一个天分不是很高的高中一年级学生甚至 可能搞不清楚这个函数的功能,你应该更严格的遵守最大限制。 进行函数拆分,并为之取个具有描述性的名字(如果你觉得其对性能要求严格的话,你 可以要求编译器将它们内联展开,它往往会比你更好的完成任务。 ) 函数另外一个衡量标准是局部变量的数量。通常来说,不应超过 5-10 个,否则这个函 数就有问题了。需要重新考虑一下,把它分拆成更小的函数。这是为什么呢?人的大脑一般 可以轻松的同时跟踪 7 个不同的事物,如果再多的话,就会糊涂了。即便你聪颖过人,也可 能会记不清你 2 个星期前做过的事情。 在源文件里,使用空行隔开不同的函数。如果该函数需要被导出,它的 EXPORT*宏应 该紧贴在它的结束大括号之下。比如: int system_is_up(void) { return system_state == SYSTEM_RUNNING; } EXPORT_SYMBOL(system_is_up); 在函数原型中,包含函数名和它们的数据类型。虽然 C 语言里没有这样的要求,但在 Linux 里这是首选的做法,因为这样可以很简单的给读者提供更多的有价值的信息。 第七节 集中函数出口
最好也不要把多个赋值语句放在同一行。 内核代码应该是非常非常简单的!请避免使用过于巧妙的表达式^^ 除了注释、文档和 Kconfig 之外,最好不要使用空格来缩进,前面的例子就是一个反面 典型^^ 选择一个合适的编辑器,并且不要在行尾留空格! 第二节 适当的换行 代码风格的意义在于, 即使采用不同的编辑器, 仍然可以保证代码的可读性和可维护性。 每一行长度的限制是八十列,并且强烈建议应该是首选的。 长度超过八十列的语句可以分成几个有意义的片段,每个片段要明显短于原来的语句, 并且放的位置也要明显的靠右。 这个规则对于有很长参数列表的函数同也同样适用。 长字符 串也要打散成较短的字符串。 只有一种情况, 即超过八十列可以大幅度提高可读性并且不会 隐藏信息的情况,可以例外^^ void fun(int a, int b, int c) { if (condition) printk(KERN_WARNING "Warning this is a long printk with " "3 parameters a: %u b: %u " "c: %u \n", a, b, c); else next_statement; } 第三节 放置大括号和空格 C 语言风格中另外一个问题是大括号的放置。这和缩进的大小不一样,选择或者是放弃 某种放置策略几乎没有技术上的原因,但首选的方式,就像 Kernighan 和 Ritchie 展示给我 们的,是把起始大括号放在行尾,而把结束大括号放在行首,所以: if (x is true) { we do y } 这适用于所有的非函数语句块(if、switch、for、while、do) 。比如: switch (action) { case KOBJ_ADD: return "add"; case KOBJ_REMOVE: return "remove"; case KOBJ_CHANGE: return "change"; default: return NULL;
} 不过呢,有一种特殊情况,函数定义:它们的起始大括号放置于下一行的开头,就象这 样: int function(int x) { body of function } 全世界的异端可能会抱怨这个自相矛盾的规则,呃。 。 。确实是自相矛盾,不过所有思想 健全的人都知道,K&R 是正确的,K&R 是正确的。 。 。况且,不管怎样说,函数都是特殊的 (在 C 语言中,函数是不能嵌套定义的)^^ 一般来说结束大括号应独自占据一行, 除非它后面跟着同一个语句的剩余部分, 比如说 do 语句中的“while”或者 if 语句中的“else” ,像这样: do { body of do-loop } while (condition); 和 if (x == y) { .. } else if (x > y) { ... } else { .... } 理由:K&R。 当然这样做也是有好处的,可以使空(或者差不多空的)行的数量最小化,同时不损失 可读性。因此,由于你的屏幕上的新行的供应不是可回收的资源(想想这是 25 行的终端屏 幕) ,你将会有更多的空行来放置注释。 仅有一个单独的语句时,不用加不必要的大括号。 if (condition) action(); 有一种情况需要注意, 当某个条件语句的一个分支为单独语句, 而另一个分支为多条语 句,这时应该两个分支里都使用大括号。 if (condition) { do_this(); do_that(); } else { otherwise(); }
第 3.1 节 空格 Linux 内核中空格的使用主要取决于它是用于函数还是关键字。除了 sizeof、typeof、 alignof 和__attribute__外, 其余的关键字后都要加一个空格, 主要是因为它们有点像函数 (它 们在 Linux 里也常常伴随小括号使用, 尽管这类小括号不是必需的, 就像 “struct fileinfo info” 声明过后的“sizeof info” ) 。 所以下面这几个关键字之后要放一个空格: if, switch, case, for, do, while 但是 sizeof、typeof、alignof 或者__attribute__这些关键字后面,就不要放了。例如, s = sizeof(struct file); 不要在小括号内的表达式两侧加空格。这是一个反例: s = sizeof( struct file );
C 语言是一门朴素的语言,那么命名也应该如此。和 Modula-2 和 Pascal 程序员不一样, C 程序员不会使用类似 ThisVariableIsATemporaryCounter 这样酷毕的名字,而仅用“tmp”就 可以了,这样写起来更容易,也不会另其难以理解。 尽管如此, 给全局变量定义一个一目了然的名字还是必须的。 如果谁把全局变量定义成 “foo” ,应该拉出去毙了^^ 全局变量需要一个一目了然的名字, 全局函数也是这样。 如果你有一个用来统计活动用 户数量的函数,你应该命名为“ count_active_users() ”或者是类似的名字,而不应该叫 "cntusr()"。 在函数名中包含函数类型的做法(所谓的匈牙利命名法)应该是脑子坏掉了-无论如何 编译器是知道那些数据类型,并且能够进行类型检查,这样做只会困扰程序员。难怪微软的 程序满是 BUG^^ 局部变量应该言简意赅。如果需要定义一个变量来表示循环记数器,它应该被命名为 “i” 。命名为“loop_counter”是没什么好处的,如果它没有被误解的话。同理,只要是临 时的变量,不管什么类型都可以定义为“tmp” 。 可如果你怕混淆了本地变量名,你就遇到了另一个问题,叫做函数-增长-荷尔蒙-失衡综合症。请看第六节(函数) 。 第五节:Typedef 请不要定义类似“vps_t”之类的类型。 使用 typedef 来定义结构和指针的别名是错误的,当你看见代码里面有这样一句, vps_t a; “a”是什么呢? 反过来,如果代码这样写, struct virtual_container *a; 你就能知道"a"是什么了。 许多人认为 typedef 能帮助提高程序可读性,但事实确不是这样的。它们只在下列情况 下有用: (a) 完全不透明的对象(这种情况要主动隐藏这个对象的实际意义) 。例如: “pte_t”等 不透明对象,你只能用合适的访问函数来访问它们。注意!不透明性和“访问函数本身”是 不好的。我们使用 pte_t 等类型的原因在于确实是完全没有任何共用的可访问信息。 (b) 定义清晰的整数类型,这样就可以帮助我们避免把"int"和"long"混淆。u8/u16/u32 是完美的 typedef,不过它们更符合(d)中所言,而不是这里。再次注意!必须要出师有名! 如果某个变量是“unsigned long“,那么没有必要这样做, typedef unsigned long myflags_t; 不过如果有一个明确的原因,比如它在某种情况下可能会是一个“unsigned int”而在其 他情况下可能为“unsigned long” ,那么请不要犹豫,务必使用 typedef。
但是一元操作符后不要加空格: & * + ~ ! sizeof typeof alignof __attribute__ defined