美文网首页
编程基本功-细节定成败

编程基本功-细节定成败

作者: 北溟微个尘 | 来源:发表于2018-04-20 18:27 被阅读63次

引言

看武侠都知道,即便你的武艺再高,如果内力跟不上,那在对手面前也只是花拳绣腿。编程也一样,即便你写的逻辑再深、业务再复杂,如果你的代码没有人能看懂(过段时间自己也懵逼了),下次再解决类似问题又得花费很长时间来处理。由此可说明你没有一套好的内功心法,无法积攒自己的内功。

小测试

让我们先来做个测试。看你心中的高手(或者自己)符合以下几条。

  1. 真正的程序员没有进度表,只有讨好领导的马屁精才有进度表,真正的程序员会让领导提心吊胆。
  2. 真正的程序员不写使用说明书,用户应当自己去猜想程序的功能。
  3. 真正的程序员几乎不写代码的注释,如果注释很难写,它理所当然也很难读。
  4. 真正的程序员不画流程图,原始人和文盲才会干这事。
  5. 真正的程序员不看参考手册,新手和胆小鬼才会看。
  6. 真正的程序员不写文档也不需要文档,只有看不懂程序的笨蛋才用文档。
  7. 真正的程序员认为自己比用户更明白用户需要什么。
  8. 真正的程序员不接受团队开发的理念,除非他自己是头头。
  9. 真正的程序员的程序不会在第一次就正确运行,但是他们愿意守着机器进行若干个30小时的调试改错。
  10. 真正的程序员不会在上午 9:00 到下午 5:00 之间工作,如果你看到他在上午9:00 工作,这表明他从昨晚一直干到现在。
    ...

是否心中很信仰这样的程序员?的确,这样‘真正的’程序员无拘无束、行云流水,我一开始是很向往的。在拜读林锐的《高质量C++、C编程指南》之后,逐渐发现,若照此修炼,就只能花拳绣腿。因此练好内功,才能刚!

内功修炼法精简版(正文)

1.程序版式

【规则1】一行代码只做一件事,如只定义一个变量,或只写一条语句。便于阅读,便于注释。

int width;   //宽度  
int height;  //高度
int depth;   //深度

【建议】尽可能在定义变量的同时初始化该变量(就近原则)

int width = 10;   //宽度  
int height = 10;  //高度
int depth = 10;   //深度

【规则2】if、for、while、do 等语句自占一行,执行语句不得紧跟其后。不论 执行语句有多少都要加{}。

if (width < height) 
{
   dosomething();
}

【规则3】空格问题
1.关键字之后要留空格。象 const、virtual、inline、case 等关键字之后 至少要留一个空格。if、for、while 等关键字之后应留一个 空格再跟左括号‘(’,以突出关键字。

  1. ‘ ,’之后要留空格,如 Function(x, y, z)。如果‘;’不是一行的结束
    符号,其后要留空格,如 for (initialization; condition; update)。
  2. 赋值操作符、比较操作符、算术操作符、逻辑操作符、位域操作符,如“=”、“+=”“>=”、“<=”、“+”、“*”、“%”、“&&”、“||”、“<<”,“^”等二元操作符的前后应当加空格。
    ...
    详见如下代码
void Func1(int x, int y, int z); // 良好的风格 
void Func1 (int x,int y,int z);  // 不良的风格

if (year >= 2000)                // 良好的风格 
if(year>=2000)                   // 不良的风格
if ((a>=b) && (c<=d))            // 良好的风格
if(a>=b&&c<=d)                   // 不良的风格

for (i=0; i<10; i++)             // 良好的风格
for(i=0;i<10;i++)                // 不良的风格
for (i = 0; I < 10; i ++)        // 过多的空格

x = a < b ? a : b;              // 良好的风格 
x=a<b?a:b;                      // 不好的风格

int *x = &y;                    // 良好的风格 
int * x = & y;                  // 不良的风格

array[5] = 0;     // 不要写成 array [ 5 ] = 0;

【规则4】内容对齐

void Function(int x) 
{
    ... // program code 
}

if (condition) 
{
    ... // program code 
}
else 
{
    ... // program code 
}

【规则5】长行拆分:长表达式要在低优先级操作符处拆分成新行,操作符放在新行之首(以 便突出操作符)。拆分出的新行要进行适当的缩进,使排版整齐,语句可读。

if ((very_longer_variable1 >= very_longer_variable12)
   && (very_longer_variable3 <= very_longer_variable14) 
   && (very_longer_variable5 <= very_longer_variable16))
{
    dosomething();
}

virtual CMatrix CMultiplyMatrix (CMatrix leftMatrix, 
                                 CMatrix rightMatrix);
                                 
for (very_longer_initialization; 
     very_longer_condition;
     very_longer_update)
{
    dosomething();
}                               

【规则6】注释
1、注释是对代码的“提示”,而不是文档。程序中的注释不可喧宾夺主, 注释太多了会让人眼花缭乱。注释的花样要少。
2、如果代码本来就是清楚的,则不必加注释。否则多此一举,令人厌烦。例如 i++; //i 加 1,多余的注释
3、当代码比较长,特别是有多重嵌套时,应当在一些段落的结束处加注释,便于阅读。

/*
* 函数介绍:
* 输入参数:
* 输出参数:
* 返回值 :
*/
void Function(float x, float y, float z)
{
    ... 
}

if (...) 
{
    ...
    while (...) 
    {
        ...
    } // end of while 
    ...
} // end of if
2.命名

【规则1】变量和参数用小写字母开头的单词组合而成。 例如:

BOOL flag;
int drawMode;

【规则2】常量全用大写的字母,用下划线分割单词。 例如:

const int MAX = 100;
const int MAX_LENGTH = 1000;

【规则3】静态变量加前缀 s_(表示 static)。 全局变量,则使全局变量加前缀 g_(表示 global)。
例如:

void Init(...) 
{
    static int s_initValue; // 静态变量
    ... 
}

int g_howManyPeople;  // 全局变量 
int g_howMuchMoney;   // 全局变量
3.表达式和基本语句


【规则1】不要有多用途的复合表达式。
例如:
d = (a = b + c) + r ;

该表达式既求 a 值又求 d 值。应该拆分为两个独立的语句:

a = b + c; 
d = a + r;

【规则2】不可将布尔变量直接与 TRUE、FALSE 或者 1、0 进行比较。
假设布尔变量名字为 flag,它与零值比较的标准 if 语句如下:

if (flag)    //表示flag为真
if (!flag)   //表示 flag 为假

其它的用法都属于不良风格,例如:

if (flag == TRUE) 
if (flag == 1 )
if (flag == FALSE) 
if (flag == 0)

【规则3】应当将整型变量用“==”或“!=”直接与0比较。
假设整型变量的名字为 value,它与零值比较的标准 if 语句如下:

if (value == 0)
if (value != 0)

不可模仿布尔变量的风格而写成

if (value)   // 会让人误解 value 是布尔变量 
if (!value)

【规则4】应当将指针变量用“==”或“!=”与NULL比较。
指针变量的零值是“空”(记为 NULL)。尽管 NULL 的值与 0 相同,但是两者意义不 同。假设指针变量的名字为 p,它与零值比较的标准 if 语句如下:

if (p == NULL)   // p 与 NULL 显式比较,强调 p 是指针变量
if (p != NULL)

有时候我们可能会看到 if (NULL == p) 这样古怪的格式。不是程序写错了,是程 序员为了防止将 if (p == NULL) 误写成 if (p = NULL),而有意把 p 和 NULL 颠倒。编 译器认为 if (p = NULL) 是合法的,但是会指出 if (NULL = p)是错误的,因为 NULL 不能被赋值。
比如OC的懒加载方法中:

if (nil == object)
{
    object = [NSObject alloc] init];
    ...
} 

【规则5】循环语句效率
1.在多重循环中,如果有可能,应当将最长的循环放在最内层,最短的 循环放在最外层,以减少 CPU 跨切循环层的次数。

// 低效率
for (row=0; row<100; row++) 
{
    for ( col=0; col<5; col++ ) 
    {
        sum = sum + a[row][col]; 
    }
} 
// 高效率
for (col=0; col<5; col++ ) 
{
    for (row=0; row<100; row++) 
    {
        sum = sum + a[row][col]; 
    }
}

2.如果循环体内存在逻辑判断,并且循环次数很大,宜将逻辑判断移到循环体的外面。

// 效率低但代码简洁 若N较小适用,执行效率劣势不大
for (i=0; i<N; i++) 
{
    if (condition) 
        DoSomething();
    else 
        DoOtherthing();
}

// 效率高但代码冗余 若N较大适用,执行效率较高
if (condition) 
{
    for (i=0; i<N; i++) DoSomething();
} 
else 
{
    for (i=0; i<N; i++) DoOtherthing();
}

3.建议for语句的循环控制变量的取值采用“半开半闭区间”写法。
半开半闭区间写法:for (int x=0; x<N; x++)
闭区间写法: for (int x=0; x<=N-1; x++)

4.常量

const 与 #define 的比较

【规则1】能用const的地方尽量用const来的代替#define,由于宏常量没有数据类型,const定义的常量编译器可以进行数据类型的安全检查。

【规则2】把公开的常量放在声明文件中,不公开的常量放在实现文件中。
【规则3】如果某一常量与其它常量密切相关,应在定义中包含这种关系。例如:

const float RADIUS = 100;
const float DIAMETER = RADIUS * 2;
5.内存管理

【一】杜绝“野指针”
“野指针”不是 NULL 指针,是指向“垃圾”内存的指针。人们一般不会错用 NULL 指针,因为用 if 语句很容易判断。但是“野指针”是很危险的,if 语句对它不起作用。
成因:
1.指针未初始化。指针刚创建时不会自动置为NULL,需要置为NULL或指向合法内存。

char *p = NULL;
char *str = (char *) malloc(100);

2.指针p被free或者delete之后,没有置为NULL,会让人误以为p是个合法指针。错误案例如下:

char *p = (char *) malloc(100);
strcpy(p, “hello”);
free(p); // p 所指的内存被释放,但是 p 所指的地址仍然不变 
...
if(p != NULL) // 没有起到防错作用
{
    strcpy(p, “world”); // 出错 
}

3.指针操作超越了变量的作用范围。这种情况让人防不胜防,示例程序如下:

class A
{ 
public:
    void Func(void){ cout << “Func of class A” << endl; } 
};
    
void Test(void) 
{
    A *p; 
        {
            A a;
            p = &a;    // 注意 a 的生命期 
        }
    p->Func();     // p 是“野指针” 
}

【二】malloc/free 的使用要点
函数 malloc 的原型如下:

void * malloc(size_t size);

用 malloc 申请一块长度为 length 的整数类型的内存,程序如下:

int *p = (int *) malloc(sizeof(int) * length);

【注1】malloc 返回值的类型是 void *,所以调用malloc要进行显示转换一下类型。
【注2】malloc 本身不识别申请的内存类型,只关心内存的总字节数。由于不同位数的操作系统数据的字节又不一样,所以需要使用sizeof来计算所占字节数。

函数 free 的原型如下:

void free( void * memblock );

为什么 free 函数不象 malloc 函数那样复杂呢?这是因为指针 p 的类型以及它所指 的内存的容量事先都是知道的,语句 free(p)能正确地释放内存。如果 p 是 NULL 指针, 那么 free 对 p 无论操作多少次都不会出问题。如果 p 不是 NULL 指针,那么 free 对 p 连续操作两次就会导致程序运行错误。

相关文章

  • 编程基本功-细节定成败

    引言 看武侠都知道,即便你的武艺再高,如果内力跟不上,那在对手面前也只是花拳绣腿。编程也一样,即便你写的逻辑再深、...

  • 细节定成败

    抄录一幅挂儿童房的日常生活警句,可怜天下父母心! 第一次用简体及格式写这种内容,不太适应,挺难把控的。

  • 细节定成败

    最近,我读了《细节决定成败》一书,颇为作者入木三分的见解折服,让人不得不承认:一个细节时代正悄然而至。 细节是一种...

  • 细节定成败

    提笔起因:老妈的吐槽 今晚上床睡觉时,甩掉了自己的拖鞋,鞋底接触在地板上发出“啪”的一声响。妈妈从客厅走进我的卧室...

  • 细节觉定成败

    最近一直在和李老师在定投课堂学习,我认识李老师还是在知乎上听他的课《一小时建立终身受用的阅读操作系统》,我特别喜欢...

  • 筹备教学基本功大赛现场有感

    市基本功大赛在我校举行,这个周末紧张的准备着。在准备的过程中学到了注意细节,设计评分。 细节决定成败, ...

  • 企业歌曲?细节定成败!

    声明:以下文字均转自北京问鼎之音文化发展有限公司官方网站,转载请注明出处。 如何衡量一首企业歌曲作品是否成功,是否...

  • 企业歌曲?细节定成败!

    声明:以下文字均转自北京问鼎之音文化发展有限公司官方网站,转载请注明出处。 如何衡量一首企业歌曲作品是否成功,是否...

  • 细节见人品,定成败

    01 时光如白驹过隙,一去不返。转眼间,距离高中毕业,已整整十载有余。 班里组织同学聚会,因为十年意义不同,只要能...

  • 掰一掰那些会破坏美好生活的坏习惯(一)

    以前有本书,叫细节决定成败,我感觉不一定细节能决定成败这么大的事情,但是细节确确实实会影响生活的品质。 这篇文章就...

网友评论

      本文标题:编程基本功-细节定成败

      本文链接:https://www.haomeiwen.com/subject/rsmlxftx.html