《SQL基础教程》简要总结 《设计师要懂心理学》读书笔记 MySQL与MariaDB学习笔记 WDT (Folly) 安装指南 -- CentOS 7 [solved]Page build failed(Jekyll) 数据包过滤及分析实例 tshark tcpdump Scala Tour 学习总结 “Docker容器和容器云”读书笔记(1) “Docker Practice”读书笔记 “图解基础设施设计模式”小结 “图解服务器端网络架构”小结 Python网络安全编程 数据包解析笔记 华为挑战赛(1) DDoS攻击防御与云服务 基于网络回溯分析技术的异常行为分析 “Linux程序设计”小结(进程间通信) C语言编程规范(华为软件精英挑战赛) 2017阿里在线编程题--单源最短路径问题 2017年阿里在线编程题-- 数串分组 Uinx/Linux上的帮助查询命令 你懂C,所以C++不在话下 一篇特别长的总结(C专家编程) 程序员面试金典--笔记(精华篇) C陷阱与缺陷--笔记 半小时搭建电子商务网站--opencart linux网络知识和工具(持续更新) 网卡参数查询及设置工具ethtool 高性能流量生成工具trafgen(DDoS模拟) Linux流量控制工具TC 流量控制工具TC详细说明 tcpdump过滤数据包,结果不对? Lecture 网络攻击与防御技术笔记 gotgit-git权威指南 高效使用MacOS所要知道的 shell内置字符串处理 配置ntp(知其所以然) 360黑客攻防技术分享会--记录 中毒U盘恢复--快捷键病毒 Tor--anonymity network介绍(PPT) IBM bluemix 再读《Linux Shell脚本攻略》 linux shell 学习摘记(9) linux shell 学习摘记(8) linux shell 学习摘记(7) linux shell 学习摘记(6) linux shell 学习摘记(5) linux shell 学习摘记(4) linux shell 学习摘记(3) linux shell 学习摘记(2) linux shell 学习摘记(1) firefox vim 插件 vimperator A Byte of Vim 笔记 windows注册表小知识 安全测试工具篇(开源&商业) 安全及性能测试工具(网站收集) 性能测试工具 屡试不爽的“3个”iPad使用技巧 Shell Shortcuts(和Tab键一样实用) vim--自动添加jekyll post信息头 vim 自动给文件添加头部信息 GitHub Tips (很实用,值得收藏) Linux路由、防火墙、NAT命令

C语言编程规范(华为软件精英挑战赛)

2017年03月12日

原文链接: http://codeshold.me/2017/03/c_programming_specification.html

参加华为软件精英挑战赛,复习了下基本的C语言编程规范,并做了小结!

C语言编程规范

  1. 头文件
    • 编译过程
      QQ截图20170312103751.png-312.8kB
    • 头文件职责单一:头文件插入不简单,会占用不少的时间
      • VC预编译头的选项???
        • 防止一些重复编译来达到加快编译速度的一个技术
        • 在编译时,头文件不会直接参与编译,而是在预处理时与cpp文件合并后再参与编译。有些头文件几乎是所有cpp文件都需要包含的,如<stdio.h>,<windows.h>等,这样这些文件就需要在每个包含它的cpp文件中重复编译。早些时候,这些头文件不大,重复编译也浪费不了多少时间。然而到了MFC(Microsoft Foundation Classes)出现的时候,其头文件变得超级大,如就一个就长达6000多行,这样重复编译这些长的头文件就会造成更长的编译时间。为了解决这个问题,VC++编译器**把这些公共头文件事先单独编译,然后在编译包含它的cpp文件时,就直接使用头文件编译结果参与cpp文件的后续编译任务**。这种“一次编译,多次使用”的方法,确实能减少编译时间。(`stdafx.h`, `stdafx.cpp`)
    • 禁止包含用不到的头文件
    • 放置接口声明、不适合放实现
    • 禁止在头文件中定义变量:可能出现重定义错误
    • 头文件应向稳定方向包含:一个头文件的变化,会导致所有包含该头文件代码的重新编译
    • 禁止头文件循环依赖: 减少“依赖深度过深的错误”
    • 总是编写内部的#ifndef保护符:#ifndef A_H_ ...
    • 头文件应当自包含
    • 禁止extern "C"中包含头文件!
      • extern "C"的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
      • 比如说你用C 开发了一个DLL 库,为了能够让C ++语言也能够调用你的DLL输出(Export)的函数,你需要用extern "C"来强制编译器不要修改你的函数名。
      • extern “C”用法解析extern "C" 用来修饰变量和函数的!
      • C、C++接口间的相互调用举例
    • 每个c文件应有一个同名h文件
    • 设计文档写出来的时候就过时了!头文件才是王道!
      QQ截图20170312104621.png-309.8kB
  2. 函数编程规范
    • 圈复杂度小于7:一个函数可以执行的路径条数
    • 函数要短小(推荐小于50行, 每行80个)
    • 嵌套层数小于5
    • 职责单一
    • 抽象层单一:同一层的抽象在同一层
    • 参数不超过3个
    • 避免重复
    • 避免重入问题: 锁机制
    • 不要返回局部变量
  3. 语法规范
    • 命令、注释、格式、效率、安全
      • 效率和可维护性冲突时,往往选择后者
    • 安全:通过指针访问内存(优点也是缺点)
      • 地址&内存空间:Data(常量区、全局变量区、静态变量区、堆、栈)+Code(代码区)
  4. C语言常见问题
    • 堆管理
      • 申请粒度不易过细,过细的建议使用栈空间(建议大于8字节)
    • 栈管理
      • 不要返回栈空间地址,进程间通信不要传递或返回栈变量
    • 强制类型转换(用来欺骗编译器)
    • 整数溢出
    • 字节对齐(取自身长度和对齐长度的最小值)
      • 将数据结构设置为与字节无关的(或者添加字节预留符)
      • 字节对齐说明
    • 字节序
      image_1bb0dep2n1a077e0tlp1q0qfi211.png-180.4kB
    • 编译器眼中的指针
      • 编译器就是这个脾气!
        image_1bb0dl4ce12i817mqih49cqm4i1e.png-515.8kB
      • 代码:小心取地址符号&,小心sizeof, 指针加减(按指针所指向的元素的大小移动),将数组名或字符串名的值即是其第一个元素的地址!

              [gridftp02@gf02 ~]$ cat pointer.c  #include <stdio.h>
              int main(int argc, char *argv[])
              {
                  char name_array[] = "test";
                  char *name = "test";
                            
                  printf("name address:%#x\n", name_array);
                  printf("name address:%#x\n", &name_array[0]);
                  printf("name address:%#x\n", &name_array);
                  printf("name address:%#x\n", name_array+1);
                  printf("name address:%#x\n", &name_array+1);
                  printf("name address:%#d\n", sizeof(name_array));
                  printf("==============\n");
                            
                  printf("name address:%#x\n", name);
                  printf("name address:%#x\n", &name[0]);
                  printf("name address:%#x\n", &name);
                  printf("name address:%#x\n", name+1);
                  printf("name address:%#x\n", &name+1);
                  printf("name address:%#d\n", sizeof(name));
                            
                  return 0;
              }
              [gridftp02@gf02 ~]$ gcc pointer.c 
              [gridftp02@gf02 ~]$ ./a.out 
              name address:0x50ec0a40
              name address:0x50ec0a40
              name address:0x50ec0a40
              name address:0x50ec0a41
              name address:0x50ec0a45
              name address:5
              ==============
              name address:0x400760
              name address:0x400760
              name address:0x50ec0a38
              name address:0x400761
              name address:0x50ec0a40
              name address:8
        
  5. 相关
    • 《代码简洁之道》
    • 《重构》
    • Good code is not bad code!
    • 代码检视、单元测试、集成测试、系统测试

说明

  1. 华为软件精英挑战赛,C语言规范视频
  2. 华为C语言编程规范, pdf下载链接

知识共享许可协议
SWF's Hacking Dreamonephone 创作,采用 知识共享 署名-非商业性使用 4.0 国际 许可协议进行许可。
© 2011-2017. All rights reserved by onephone. Powerd by Jekyll.