软件编程规范和范例

目  录

1 排版

6

2 注释

11

3 标识符命名

18

4 可读性

20

5 变量、结构

22

6 函数、过程

28

7 可测性

36

8 程序效率

40

9 质量保证

44

10 代码编辑、编译、审查

50

11 代码测试、维护

52

12 宏

53


1 排版

¹1-1:程序块要采用缩进风格编写,缩进的空格数为4个。

说明:对于由开发工具自动生成的代码可以有不一致。

¹1-2:相对独立的程序块之间、变量说明之后必须加空行。

示例:如下例子不符合规范。

if(!valid_ni(ni))

{

    ... // program code

}

repssn_ind= ssn_data[index].repssn_index;

repssn_ni  = ssn_data[index].ni;

 

应如下书写

if(!valid_ni(ni))

{

    ... // program code

}

 

repssn_ind= ssn_data[index].repssn_index;

repssn_ni  = ssn_data[index].ni;

¹1-3:较长的语句(>80字符)要分成多行书写,长表达式要在低优先级操作符处划分新行,操作符放在新行之首,划分出的新行要进行适当的缩进,使排版整齐,语句可读。

示例:

perm_count_msg.head.len = NO7_TO_STAT_PERM_COUNT_LEN

                          + STAT_SIZE_PER_FRAM* sizeof( _UL );

 

act_task_table[frame_id * STAT_TASK_CHECK_NUMBER +index].occupied

              = stat_poi[index].occupied;

 

act_task_table[taskno].duration_true_or_false

             = SYS_get_sccp_statistic_state( stat_item );

 

report_or_not_flag = ((taskno <MAX_ACT_TASK_NUMBER)

                     && (n7stat_stat_item_valid (stat_item))

                     && (act_task_table[taskno].result_data != 0));


¹1-4:循环、判断等语句中若有较长的表达式或语句,则要进行适应的划分,长表达式要在低优先级操作符处划分新行,操作符放在新行之首。

示例:

if((taskno < max_act_task_number)

    && (n7stat_stat_item_valid(stat_item)))

{

    ... // program code

}

 

for (i =0, j = 0; (i < BufferKeyword[word_index].word_length)

                    && (j < NewKeyword.word_length);i++, j++)

{

    ... // program code

}

 

for (i =0, j = 0; 

     (i < first_word_length) && (j< second_word_length); 

     i++, j++)

{

    ... // program code

}

¹1-5:若函数或过程中的参数较长,则要进行适当的划分。

示例:

n7stat_str_compare((BYTE *) & stat_object,

                  (BYTE *) & (act_task_table[taskno].stat_object),

                  sizeof (_STAT_OBJECT));

 

n7stat_flash_act_duration( stat_item, frame_id*STAT_TASK_CHECK_NUMBER

                                      + index,stat_object );

¹1-6:不允许把多个短语句写在一行中,即一行只写一条语句。

示例:如下例子不符合规范。

rect.length= 0;  rect.width = 0;

 

应如下书写

rect.length= 0;

rect.width  = 0;

¹1-7:if、for、do、while、case、switch、default等语句自占一行,且if、for、do、while等语句的执行语句部分无论多少都要加括号{}。

示例:如下例子不符合规范。

if(pUserCR == NULL) return;

 

应如下书写:

if(pUserCR == NULL)

{

    return;

}

1-8 使用tab缩进,不建议使用空格键

1-9:函数或过程的开始、结构的定义及循环、判断等语句中的代码都要采用缩进风格,case语句下的情况处理语句也要遵从语句缩进要求。

¹1-10:程序块的分界符(如C/C++语言的大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类的定义、结构的定义、枚举的定义以及if、for、do、while、switch、case语句中的程序都要采用如上的缩进方式。

示例:如下例子不符合规范。

for (...){

    ... // program code

}

 

if (...)

    {

    ... // program code

    }

 

voidexample_fun( void )

    {

    ... // program code

    }

 

应如下书写。

for (...)

{

    ... // program code

}

 

if (...)

{

    ... // program code

}

 

void example_fun(void )

{

    ... // program code

}

  


2 注释

¹2-1:一般情况下,源程序有效注释量必须在20%以上。

说明:注释的原则是有助于对程序的阅读理解,在该加的地方都加了,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。

2-4:函数头部应进行注释,列出:函数的目的/功能、输入参数、输出参数、返回值、调用关系(函数、表)等。

示例:下面这段函数的注释比较标准,当然,并不局限于此格式,但上述信息建议要包含在内。

/*************************************************

   Description:    // 函数功能、性能等的描述

  Param:          // 输入参数说明,包括每个参数的作

                  // 用、取值说明及参数间关系。

  Return:         // 函数返回值的说明

author:         // 作者

*************************************************/

¹2-5:边写代码边注释,修改代码同时修改相应的注释,以保证注释与代码的一致性。不再有用的注释要删除。

¹2-6:注释的内容要清楚、明了,含义准确,防止注释二义性。

说明:错误的注释不但无益反而有害。

规则2-7:避免在注释中使用缩写,特别是非常用缩写。

说明:在使用缩写时或之前,应对缩写进行必要的说明。

¹2-8:注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。

示例:如下例子不符合规范。

例1:

/* getreplicate sub system index and net indicator */

 

 

repssn_ind= ssn_data[index].repssn_index;

repssn_ni= ssn_data[index].ni;

 

例2:

repssn_ind= ssn_data[index].repssn_index;

repssn_ni= ssn_data[index].ni;

/* getreplicate sub system index and net indicator */

 

应如下书写

/* getreplicate sub system index and net indicator */

repssn_ind= ssn_data[index].repssn_index;

repssn_ni= ssn_data[index].ni;

¹2-9:对于所有有物理含义的变量、常量,如果其命名不是充分自注释的,在声明时都必须加以注释,说明其物理含义。变量、常量、宏的注释应放在其上方相邻位置或右方。

示例:

/* activestatistic task number */

#defineMAX_ACT_TASK_NUMBER 1000

 

#defineMAX_ACT_TASK_NUMBER 1000 /* active statistic task number */

¹2-10:数据结构声明(包括数组、结构、类、枚举等),如果其命名不是充分自注释的,必须加以注释。对数据结构的注释应放在其上方相邻位置,不可放在下面;对结构中的每个域的注释放在此域的右方。

示例:可按如下形式说明枚举/数据/联合结构。

/* sccpinterface with sccp user primitive message name */

enum  SCCP_USER_PRIMITIVE

{

    N_UNITDATA_IND, /* sccp notify sccp userunit data come */

    N_NOTICE_IND,   /* sccp notify user the No.7 network can not*/

                    /* transmission thismessage */

    N_UNITDATA_REQ, /* sccp user's unit datatransmission request*/

};

¹2-11:全局变量要有较详细的注释,包括对其功能、存取时注意事项等的说明。

示例:

/* TheErrorCode when SCCP translate */

/* GlobalTitle failure, as follows */      // 变量作用、含义

/* 0 - SUCCESS   1 - GT Table error */

/* 2 - GT error  Others - no use  */       // 变量取值范围

/*only  function  SCCPTranslate() in */

/* thismodual can modify it,  and  other */

/* modulecan visit it through call */

/*the  function GetGTTransErrorCode()*/    // 使用方法

BYTEg_GTTranErrorCode; 

¹2-13:将注释与其上面的代码用空行隔开。

示例:如下例子,显得代码过于紧凑。

/* codeone comments */

programcode one

/* codetwo comments */

programcode two

 

应如下书写

/* codeone comments */

programcode one

 

/* codetwo comments */

programcode two

¹2-14:对变量的定义和分支语句(条件分支、循环语句等)尽量编写注释。

说明:这些语句往往是程序实现某一特定功能的关键,对于维护人员来说,良好的注释帮助更好的理解程序,有时甚至优于看设计文档。

¹2-15:对于switch语句下的case语句,如果因为特殊情况需要处理完一个case后进入下一个case处理,必须在该case语句处理完、下一个case语句前加上明确的注释。

说明:这样比较清楚程序编写者的意图,有效防止无故遗漏break语句。

示例(注意斜体加粗部分):

caseCMD_UP:  

    ProcessUp();

    break;

 

caseCMD_DOWN:

    ProcessDown();

    break;

 

caseCMD_FWD: 

    ProcessFwd();

   

if (...)

{

    ...

    break;

}

else

{

    ProcessCFW_B();   // now jump into case CMD_A

}

 

caseCMD_A:   

    ProcessA();   

    break;

 

caseCMD_B:   

    ProcessB();   

    break;

 

caseCMD_C:   

    ProcessC();   

    break;

 

caseCMD_D:   

    ProcessD();   

    break;

...

½2-1:避免在一行代码或表达式的中间插入注释。

说明:除非必要,不应在代码或表达中间插入注释,否则容易使代码可理解性变差。

½2-2:通过对函数或过程、变量、结构等正确的命名以及合理地组织代码的结构,使代码成为自注释的。

说明:清晰准确的函数、变量等的命名,可增加代码可读性,并减少不必要的注释。

½2-3:在代码的功能、意图层次上进行注释,提供有用、额外的信息。

说明:注释的目的是解释代码的目的、功能和采用的方法,提供代码以外的信息,帮助读者理解代码,防止没必要的重复注释信息。

示例:如下注释意义不大。

/* if receive_flagis TRUE */

if(receive_flag)

 

而如下的注释则给出了额外有用的信息。

/* if mtpreceive a message from links */

if(receive_flag)

½2-4:在程序块的结束行右方加注释标记,以表明某程序块的结束。

说明:当代码段较长,特别是多重嵌套时,这样做可以使代码更清晰,更便于阅读。

示例:参见如下例子。

if (...)

{

    // program code

 

    while (index < MAX_INDEX)

    {

        // program code

    } /* end of while (index < MAX_INDEX) */// 指明该条while语句结束

} /* endof  if (...)*/ // 指明是哪条if语句结束

½2-5:注释格式尽量统一,建议使用“/* …… */”。

½2-6:注释应考虑程序易读及外观排版的因素,使用的语言若是中、英兼有的,建议多使用中文,除非能用非常流利准确的英文表达。

说明:注释语言不统一,影响程序易读性和外观排版,出于对维护人员的考虑,建议使用中文。


3 标识符命名

¹3-1:标识符的命名要清晰、明了,有明确含义,同时使用完整的单词或大家基本可以理解的缩写,避免使人产生误解。

说明:较短的单词可通过去掉“元音”形成缩写;较长的单词可取单词的头几个字母形成缩写;一些单词有大家公认的缩写。

示例:如下单词的缩写能够被大家基本认可。

temp 可缩写为  tmp  ;

flag 可缩写为  flg  ;

statistic 可缩写为  stat ;

increment 可缩写为  inc  ;

message 可缩写为  msg  ;

¹3-2:命名中若使用特殊约定或缩写,则要有注释说明。

说明:应该在源文件的开始之处,对文件中所使用的缩写或约定,特别是特殊的缩写,进行必要的注释说明。

¹3-3:自己特有的命名风格,要自始至终保持一致,不可来回变化。

说明:个人的命名风格,在符合所在项目组或产品组的命名规则的前提下,才可使用。(即命名规则中没有规定到的地方才可有个人命名风格)。

¹3-4:对于变量命名,禁止取单个字符(如i、j、k...),建议除了要有具体含义外,还能表明其变量类型、数据类型等,但i、j、k作局部循环变量是允许的。

说明:变量,尤其是局部变量,如果用单个字符表示,很容易敲错(如i写成j),而编译时又检查不出来,有可能为了这个小小的错误而花费大量的查错时间。

示例:下面所示的局部变量名的定义方法可以借鉴。

intliv_Width

其变量名解释如下:

       l     局部变量(Local)  (其它:g    全局变量(Global)...)

       i     数据类型(Interger)

       v     变量(Variable)   (其它:c    常量(Const)...)

       Width 变量含义

这样可以防止局部变量与全局变量重名。

¹3-5:命名规范必须与所使用的系统风格保持一致,并在同一项目中统一,比如采用UNIX的全小写加下划线的风格或大小写混排的方式,不要使用大小写与下划线混排的方式,用作特殊标识如标识成员变量或全局变量的m_和g_,其后加上大小写混排的方式是允许的。

示例: Add_User不允许,add_user、AddUser、m_AddUser允许。

½3-1:除非必要,不要用数字或较奇怪的字符来定义标识符。

示例:如下命名,使人产生疑惑。

#define_EXAMPLE_0_TEST_

#define_EXAMPLE_1_TEST_

voidset_sls00( BYTE sls );

 

应改为有意义的单词命名

#define_EXAMPLE_UNIT_TEST_

#define_EXAMPLE_ASSERT_TEST_

voidset_udt_msg_sls( BYTE sls );

½3-2:在同一软件产品内,应规划好接口部分标识符(变量、结构、函数及常量)的命名,防止编译、链接时产生冲突。

说明:对接口部分的标识符应该有更严格限制,防止冲突。如可规定接口部分的变量与常量之前加上“模块”标识等。

½3-3:用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

说明:下面是一些在软件中常用的反义词组。

add /remove       begin / end        create / destroy

insert /delete    first / last       get / release

increment/ decrement                 put / get

add /delete       lock / unlock      open / close

min /max          old / new          start / stop

next /previous    source / target    show / hide

send /receive     source / destination

cut /paste        up / down

示例:

int  min_sum;

int  max_sum;

int  add_user( BYTE *user_name );

int  delete_user( BYTE *user_name );

½3-4:除了编译开关/头文件等特殊应用,应避免使用_EXAMPLE_TEST_之类以下划线开始和结尾的定义。

 


4 可读性

¹4-1:注意运算符的优先级,并用括号明确表达式的操作顺序,避免使用默认优先级。

说明:防止阅读程序时产生误解,防止因默认的优先级与设计思想不符而导致程序出错。

示例:下列语句中的表达式

word =(high << 8) | low     (1)

if ((a |b) && (a & c))      (2)

if ((a |b) < (c & d))       (3)

如果书写为

high<< 8 | low

a | b&& a & c

a | b <c & d

由于

high<< 8 | low = ( high << 8) | low,

a | b&& a & c = (a | b) && (a & c),

(1)(2)不会出错,但语句不易理解;

a | b <c & d = a | (b < c) & d,(3)造成了判断条件出错。

¹4-2:避免使用不易理解的数字,用有意义的标识来替代。涉及物理状态或者含有物理意义的常量,不应直接使用数字,必须用有意义的枚举或宏来代替。

示例:如下的程序可读性差。

if(Trunk[index].trunk_state == 0)

{

    Trunk[index].trunk_state = 1;

    ... // program code

}

 

应改为如下形式。

#defineTRUNK_IDLE 0

#defineTRUNK_BUSY 1

 

if(Trunk[index].trunk_state == TRUNK_IDLE)

{

    Trunk[index].trunk_state = TRUNK_BUSY;

    ... // program code

}

½4-1:源程序中关系较为紧密的代码应尽可能相邻。

说明:便于程序阅读和查找。

示例:以下代码布局不太合理。

rect.length= 10;

char_poi =str;

rect.width= 5;

 

若按如下形式书写,可能更清晰一些。

rect.length= 10;

rect.width= 5; // 矩形的长与宽关系较密切,放在一起。

char_poi =str;

½4-2:不要使用难懂的技巧性很高的语句,除非很有必要时。

说明:高技巧语句不等于高效率的程序,实际上程序的效率关键在于算法。

示例:如下表达式,考虑不周就可能出问题,也较难理解。

* stat_poi++ += 1;

 

* ++stat_poi += 1;

 

应分别改为如下。

*stat_poi+= 1;

stat_poi++;     // 此二语句功能相当于“ *stat_poi ++ += 1; ”

 

++stat_poi;

*stat_poi+= 1; // 此二语句功能相当于“ * ++ stat_poi += 1; ”


5 变量、结构

¹5-1:去掉没必要的公共变量。

说明:公共变量是增大模块间耦合的原因之一,故应减少没必要的公共变量以降低模块间的耦合度。

¹5-2:仔细定义并明确公共变量的含义、作用、取值范围及公共变量间的关系。

说明:在对变量声明的同时,应对其含义、作用及取值范围进行注释说明,同时若有必要还应说明与其它变量的关系。

¹5-3:明确公共变量与操作此公共变量的函数或过程的关系,如访问、修改及创建等。

说明:明确过程操作变量的关系后,将有利于程序的进一步优化、单元测试、系统联调以及代码维护等。这种关系的说明可在注释或文档中描述。

示例:在源文件中,可按如下注释形式说明。

RELATION    System_Init    Input_Rec   Print_Rec   Stat_Score

Student     Create         Modify       Access      Access

Score       Create         Modify       Access      Access, Modify

 

注:RELATION为操作关系;System_Init、Input_Rec、Print_Rec、Stat_Score为四个不同的函数;Student、Score为两个全局变量;Create表示创建,Modify表示修改,Access表示访问。

其中,函数Input_Rec、Stat_Score都可修改变量Score,故此变量将引起函数间较大的耦合,并可能增加代码测试、维护的难度。

¹5-4:当向公共变量传递数据时,要十分小心,防止赋与不合理的值或越界等现象发生。

说明:对公共变量赋值时,若有必要应进行合法性检查,以提高代码的可靠性、稳定性。

¹5-5:防止局部变量与公共变量同名。

说明:若使用了较好的命名规则,那么此问题可自动消除。

5-6:结构中元素的个数应适中。若结构中元素个数过多可考虑依据某种原则把元素组成不同的子结构,以减少原结构中元素的个数。

说明:增加结构的可理解性、可操作性和可维护性。

示例:假如认为如上的_PERSON结构元素过多,那么可如下对之划分。

typedefstruct PERSON_BASE_INFO_STRU

{

    unsigned char name[8];

    unsigned char age;

    unsigned char sex;

}PERSON_BASE_INFO;

 

typedefstruct PERSON_ADDRESS_STRU

{

    unsigned char addr[40];

    unsigned char city[15];

    unsigned char tel;

}PERSON_ADDRESS;

 

typedefstruct PERSON_STRU

{

    PERSON_BASE_INFO person_base;

    PERSON_ADDRESS person_addr;

} PERSON;

½5-10:编程时,要注意数据类型的强制转换。

说明:当进行数据类型强制转换时,其数据的意义、转换后的取值等都有可能发生变化,而这些细节若考虑不周,就很有可能留下隐患。

½5-14:对自定义数据类型进行恰当命名,使它成为自描述性的,以提高代码可读性。注意其命名方式在同一产品中的统一。

说明:使用自定义类型,可以弥补编程语言提供类型少、信息量不足的缺点,并能使程序清晰、简洁。

示例:可参考如下方式声明自定义数据类型。

 

下面的声明可使数据类型的使用简洁、明了。

typedefunsigned char  BYTE;

typedefunsigned short WORD;

typedefunsigned int   DWORD;

 

下面的声明可使数据类型具有更丰富的含义。

typedeffloat DISTANCE;

typedeffloat SCORE;

6 函数、过程

¹6-1:对所调用函数的错误返回码要仔细、全面地处理。

¹6-2:明确函数功能,精确(而不是近似)地实现函数设计。

½6-12:函数名应准确描述函数的功能。

½6-13:使用动宾词组为执行某操作的函数命名。如果是OOP方法,可以只有动词(名词是对象本身)。

示例:参照如下方式命名函数。

voidprint_record( unsigned int rec_ind ) ;

int  input_record( void ) ;

unsignedchar get_current_color( void ) ;

建议6-15:函数的返回值要清楚、明了,让使用者不容易忽视错误情况。

说明:函数的每种出错返回值的意义要清晰、明了、准确,防止使用者误用、理解错误或忽视错误返回码。

½6-30:当一个过程(函数)中对较长变量(一般是结构的成员)有较多引用时,可以用一个意义相当的宏代替。

说明:这样可以增加编程效率和程序的可读性。

示例:在某过程中较多引用TheReceiveBuffer[FirstSocket].byDataPtr,

则可以通过以下宏定义来代替:

# definepSOCKDATA TheReceiveBuffer[FirstScoket].byDataPtr


7 可测性

¹7-1:在同一项目组或产品组内,要有一套统一的为集成测试与系统联调准备的调测开关及相应打印函数,并且要有详细的说明。

说明:本规则是针对项目组或产品组的。

¹7-2:在同一项目组或产品组内,调测打印出的信息串的格式要有统一的形式。信息串中至少要有所在模块名(或源文件名)及行号。

说明:统一的调测信息格式便于集成测试。

¹7-3:编程的同时要为单元测试选择恰当的测试点,并仔细构造测试代码、测试用例,同时给出明确的注释说明。测试代码部分应作为(模块中的)一个子模块,以方便测试代码在模块中的安装与拆卸(通过调测开关)。

说明:为单元测试而准备。

¹7-4:在进行集成测试/系统联调之前,要构造好测试环境、测试项目及测试用例,同时仔细分析并优化测试用例,以提高测试效率。

说明:好的测试用例应尽可能模拟出程序所遇到的边界值、各种复杂环境及一些极端情况等。

¹7-5:使用断言来发现软件问题,提高代码可测性。

说明:断言是对某种假设条件进行检查(可理解为若条件成立则无动作,否则应报告),它可以快速发现并定位软件问题,同时对系统错误进行自动报警。断言可以对在系统中隐藏很深,用其它手段极难发现的问题进行定位,从而缩短软件问题定位时间,提高系统的可测性。实际应用时,可根据具体情况灵活地设计断言。

示例:下面是C语言中的一个断言,用宏来设计的。(其中NULL为0L)

#ifdef_EXAM_ASSERT_TEST_  // 若使用断言测试

 

voidexam_assert( char * file_name, unsigned int line_no )

{

    printf( "\n[EXAM]Assert failed: %s, line %u\n",

            file_name, line_no );

    abort( );

}

 

#define  EXAM_ASSERT( condition )

    if (condition) // 若条件成立,则无动作

        NULL;

    else // 否则报告

        exam_assert( __FILE__, __LINE__ )

 

#else  // 若不使用断言测试

 

#defineEXAM_ASSERT(condition)  NULL

 

#endif  /* end of ASSERT */

¹7-6:用断言来检查程序正常运行时不应发生但在调测时有可能发生的非法情况。

¹7-7:不能用断言来检查最终产品肯定会出现且必须处理的错误情况。

说明:断言是用来处理不应该发生的错误情况的,对于可能会发生的且必须处理的情况要写防错程序,而不是断言。如某模块收到其它模块或链路上的消息后,要对消息的合理性进行检查,此过程为正常的错误检查,不能用断言来实现。

¹7-8:对较复杂的断言加上明确的注释。

说明:为复杂的断言加注释,可澄清断言含义并减少不必要的误用。

¹7-9:用断言确认函数的参数。

示例:假设某函数参数中有一个指针,那么使用指针前可对它检查,如下。

intexam_fun( unsigned char *str )

{

    EXAM_ASSERT( str != NULL );  // 用断言检查“假设指针不为空”这个条件

   

    ... //other program code

}

¹7-10:用断言保证没有定义的特性或功能不被使用。

示例:假设某通信模块在设计时,准备提供“无连接”和“连接” 这两种业务。但当前的版本中仅实现了“无连接”业务,且在此版本的正式发行版中,用户(上层模块)不应产生“连接”业务的请求,那么在测试时可用断言检查用户是否使用“连接”业务。如下。

#defineEXAM_CONNECTIONLESS 0 // 无连接业务

#defineEXAM_CONNECTION     1 // 连接业务

 

intmsg_process( EXAM_MESSAGE *msg )

{

    unsigned char service; /* message serviceclass */

 

    EXAM_ASSERT( msg != NULL );

 

service =get_msg_service_class( msg );

 

    EXAM_ASSERT( service != EXAM_CONNECTION );// 假设不使用连接业务

 

    ... //other program code

}

¹7-11:用断言对程序开发环境(OS/Compiler/Hardware)的假设进行检查。

说明:程序运行时所需的软硬件环境及配置要求,不能用断言来检查,而必须由一段专门代码处理。用断言仅可对程序开发环境中的假设及所配置的某版本软硬件是否具有某种功能的假设进行检查。如某网卡是否在系统运行环境中配置了,应由程序中正式代码来检查;而此网卡是否具有某设想的功能,则可由断言来检查。

对编译器提供的功能及特性假设可用断言检查,原因是软件最终产品(即运行代码或机器码)与编译器已没有任何直接关系,即软件运行过程中(注意不是编译过程中)不会也不应该对编译器的功能提出任何需求。

示例:用断言检查编译器的int型数据占用的内存空间是否为2,如下。

EXAM_ASSERT(sizeof( int ) == 2 );

¹7-12:正式软件产品中应把断言及其它调测代码去掉(即把有关的调测开关关掉)。

说明:加快软件运行速度。

¹7-13:在软件系统中设置与取消有关测试手段,不能对软件实现的功能等产生影响。

说明:即有测试代码的软件和关掉测试代码的软件,在功能行为上应一致。

¹7-14:用调测开关来切换软件的DEBUG版和正式版,而不要同时存在正式版本和DEBUG版本的不同源文件,以减少维护的难度。

¹7-15:软件的DEBUG版本和发行版本应该统一维护,不允许分家,并且要时刻注意保证两个版本在实现功能上的一致性。

½7-1:在编写代码之前,应预先设计好程序调试与测试的方法和手段,并设计好各种调测开关及相应测试代码如打印函数等。

说明:程序的调试与测试是软件生存周期中很重要的一个阶段,如何对软件进行较全面、高率的测试并尽可能地找出软件中的错误就成为很关键的问题。因此在编写源代码之前,除了要有一套比较完善的测试计划外,还应设计出一系列代码测试手段,为单元测试、集成测试及系统联调提供方便。

½7-2:调测开关应分为不同级别和类型。

说明:调测开关的设置及分类应从以下几方面考虑:针对模块或系统某部分代码的调测;针对模块或系统某功能的调测;出于某种其它目的,如对性能、容量等的测试。这样做便于软件功能的调测,并且便于模块的单元测试、系统联调等。

½7-3:编写防错程序,然后在处理错误之后可用断言宣布发生错误。

示例:假如某模块收到通信链路上的消息,则应对消息的合法性进行检查,若消息类别不是通信协议中规定的,则应进行出错处理,之后可用断言报告,如下例。

#ifdef_EXAM_ASSERT_TEST_ // 若使用断言测试

 

/* Notice:this function does not call 'abort' to exit program */

voidassert_report( char * file_name, unsigned int line_no )

{

    printf( "\n[EXAM]Error Report: %s, line %u\n",

            file_name, line_no );

}

 

#define  ASSERT_REPORT( condition )

    if ( condition ) // 若条件成立,则无动作

        NULL;

    else // 否则报告

        assert_report ( __FILE__, __LINE__ )

 

#else // 若不使用断言测试

 

#defineASSERT_REPORT( condition )  NULL

 

#endif /*end of ASSERT */

 

intmsg_handle( unsigned char msg_name, unsigned char * msg )

{

    switch( msg_name )

    {

        case MSG_ONE:

            ... // 消息MSG_ONE处理

            return MSG_HANDLE_SUCCESS;

   

            ... // 其它合法消息处理

   

        default:

            ... // 消息出错处理

            ASSERT_REPORT( FALSE );  // “合法”消息不成立,报告

            return MSG_HANDLE_ERROR;

    }

}


8 程序效率

¹8-1:编程时要经常注意代码的效率。

说明:代码效率分为全局效率、局部效率、时间效率及空间效率。全局效率是站在整个系统的角度上的系统效率;局部效率是站在模块或函数角度上的效率;时间效率是程序处理输入任务所需的时间长短;空间效率是程序所需内存空间,如机器代码空间大小、数据空间大小、栈空间大小等。

¹8-2:在保证软件系统的正确性、稳定性、可读性及可测性的前提下,提高代码效率。

说明:不能一味地追求代码效率,而对软件的正确性、稳定性、可读性及可测性造成影响。

¹8-3:局部效率应为全局效率服务,不能因为提高局部效率而对全局效率造成影响。

¹8-4:通过对系统数据结构的划分与组织的改进,以及对程序算法的优化来提高空间效率。

说明:这种方式是解决软件空间效率的根本办法。

示例:如下记录学生学习成绩的结构不合理。

typedefunsigned char  BYTE;

typedefunsigned short WORD;

 

typedefstruct STUDENT_SCORE_STRU

 

 

    BYTE name[8];

    BYTE age;

    BYTE sex;

    BYTE class;

    BYTE subject;

    float score;

}STUDENT_SCORE;

 

因为每位学生都有多科学习成绩,故如上结构将占用较大空间。应如下改进(分为两个结构),总的存贮空间将变小,操作也变得更方便。

typedefstruct STUDENT_STRU

{

    BYTE name[8];

    BYTE age;

    BYTE sex;

    BYTE class;

} STUDENT;

 

typedefstruct STUDENT_SCORE_STRU

{

    WORD student_index;

    BYTE subject;

    float score;

}STUDENT_SCORE;

¹8-5:循环体内工作量最小化。

说明:应仔细考虑循环体内的语句是否可以放在循环体之外,使循环体内工作量最小,从而提高程序的时间效率。

示例:如下代码效率不高。

for (ind =0; ind < MAX_ADD_NUMBER; ind++)

{

    sum += ind;

    back_sum = sum; /* backup sum */

}

 

语句“back_sum = sum;”完全可以放在for语句之后,如下。

for (ind =0; ind < MAX_ADD_NUMBER; ind++)

{

    sum += ind;

}

back_sum  = sum; /* backup sum */

½8-1:仔细分析有关算法,并进行优化。

½8-2:仔细考查、分析系统及模块处理输入(如事务、消息等)的方式,并加以改进。

½8-3:对模块中函数的划分及组织方式进行分析、优化,改进模块中函数的组织结构,提高程序效率。

说明:软件系统的效率主要与算法、处理任务方式、系统功能及函数结构有很大关系,仅在代码上下功夫一般不能解决根本问题。

½8-4:编程时,要随时留心代码效率;优化代码时,要考虑周全。

½8-5:不应花过多的时间拼命地提高调用不很频繁的函数代码效率。

说明:对代码优化可提高效率,但若考虑不周很有可能引起严重后果。

½8-6:要仔细地构造或直接用汇编编写调用频繁或性能要求极高的函数。

说明:只有对编译系统产生机器码的方式以及硬件系统较为熟悉时,才可使用汇编嵌入方式。嵌入汇编可提高时间及空间效率,但也存在一定风险。

½8-7:在保证程序质量的前提下,通过压缩代码量、去掉不必要代码以及减少不必要的局部和全局变量,来提高空间效率。

说明:这种方式对提高空间效率可起到一定作用,但往往不能解决根本问题。

½8-8:在多重循环中,应将最忙的循环放在最内层。

说明:减少CPU切入循环层的次数。

示例:如下代码效率不高。

for (row =0; row < 100; row++)

{

    for (col = 0; col < 5; col++)

    {

        sum += a[row][col];

    }

}

 

可以改为如下方式,以提高效率。

for (col =0; col < 5; col++)

{

    for (row = 0; row < 100; row++)

    {

        sum += a[row][col];

    }

}

½8-9:尽量减少循环嵌套层次。

½8-10:避免循环体内含判断语句,应将循环语句置于判断语句的代码块之中。

说明:目的是减少判断次数。循环体中的判断语句是否可以移到循环体外,要视程序的具体情况而言,一般情况,与循环变量无关的判断语句可以移到循环体外,而有关的则不可以。

示例:如下代码效率稍低。

for (ind =0; ind < MAX_RECT_NUMBER; ind++)

{

    if (data_type == RECT_AREA)

    {

        area_sum += rect_area[ind];

    }

    else

    {

       rect_length_sum += rect[ind].length;

        rect_width_sum += rect[ind].width;

    }

}

 

因为判断语句与循环变量无关,故可如下改进,以减少判断次数。

if(data_type == RECT_AREA)

{

    for (ind = 0; ind < MAX_RECT_NUMBER;ind++)

    {

        area_sum += rect_area[ind];

    }

}

else

{

    for (ind = 0; ind < MAX_RECT_NUMBER;ind++)

    {

        rect_length_sum += rect[ind].length;

        rect_width_sum  += rect[ind].width;

    }

}

½8-11:尽量用乘法或其它方法代替除法,特别是浮点运算中的除法。

说明:浮点运算除法要占用较多CPU资源。

示例:如下表达式运算可能要占较多CPU资源。

#definePAI 3.1416

radius =circle_length / (2 * PAI);

 

应如下把浮点除法改为浮点乘法。

#definePAI_RECIPROCAL (1 / 3.1416 ) // 编译器编译时,将生成具体浮点数

radius =circle_length * PAI_RECIPROCAL / 2;

½8-12:不要一味追求紧凑的代码。

说明:因为紧凑的代码并不代表高效的机器码。


9 质量保证

¹9-1:在软件设计过程中构筑软件质量。

¹9-2:代码质量保证优先原则

     (1)正确性,指程序要实现设计要求的功能。

     (2)稳定性、安全性,指程序稳定、可靠、安全。

     (3)可测试性,指程序要具有良好的可测试性。

     (4)规范/可读性,指程序书写风格、命名规则等要符合规范。

     (5)全局效率,指软件系统的整体效率。

     (6)局部效率,指某个模块/子模块/函数的本身效率。

     (7)个人表达方式/个人方便性,指个人编程习惯。

¹9-3:只引用属于自己的存贮空间。

说明:若模块封装的较好,那么一般不会发生非法引用他人的空间。

¹9-4:防止引用已经释放的内存空间。

说明:在实际编程过程中,稍不留心就会出现在一个模块中释放了某个内存块(如C语言指针),而另一模块在随后的某个时刻又使用了它。要防止这种情况发生。

¹9-5:过程/函数中分配的内存,在过程/函数退出之前要释放。

¹9-6:过程/函数中申请的(为打开文件而使用的)文件句柄,在过程/函数退出之前要关闭。

说明:分配的内存不释放以及文件句柄不关闭,是较常见的错误,而且稍不注意就有可能发生。这类错误往往会引起很严重后果,且难以定位。

示例:下函数在退出之前,没有把分配的内存释放。

typedefunsigned char BYTE;

 

intexample_fun( BYTE gt_len, BYTE *gt_code )

{

    BYTE *gt_buf;

 

    gt_buf = (BYTE *) malloc (MAX_GT_LENGTH);

    ... //program code, include check gt_buf if or not NULL.

   

    /* global title length error */

    if (gt_len > MAX_GT_LENGTH)

    {

        return GT_LENGTH_ERROR; // 忘了释放gt_buf

    }

   

    ... // other program code

}

 

应改为如下。

intexample_fun( BYTE gt_len, BYTE *gt_code )

{

    BYTE *gt_buf;

 

    gt_buf = (BYTE * ) malloc ( MAX_GT_LENGTH);

    ... // program code, include check gt_buf if or not NULL.

   

    /* global title length error */

    if (gt_len > MAX_GT_LENGTH)

    {

        free( gt_buf  ); // 退出之前释放gt_buf

        return GT_LENGTH_ERROR; 

    }

   

    ... // other program code

}

¹9-7:防止内存操作越界。

说明:内存操作主要是指对数组、指针、内存地址等的操作。内存操作越界是软件系统主要错误之一,后果往往非常严重,所以当我们进行这些操作时一定要仔细小心。

示例:假设某软件系统最多可由10个用户同时使用,用户号为1-10,那么如下程序存在问题。

#defineMAX_USR_NUM 10

unsignedchar usr_login_flg[MAX_USR_NUM]= "";

 

voidset_usr_login_flg( unsigned char usr_no )

{

    if (!usr_login_flg[usr_no])

    {

        usr_login_flg[usr_no]= TRUE;

    }

}

 

当usr_no为10时,将使用usr_login_flg越界。可采用如下方式解决。

voidset_usr_login_flg( unsigned char usr_no )

{

    if (!usr_login_flg[usr_no - 1])

    {

        usr_login_flg[usr_no - 1]= TRUE;

    }

}

¹9-8:认真处理程序所能遇到的各种出错情况。

¹9-9:系统运行之初,要初始化有关变量及运行环境,防止未经初始化的变量被引用。

¹9-10:系统运行之初,要对加载到系统中的数据进行一致性检查。

说明:使用不一致的数据,容易使系统进入混乱状态和不可知状态。

¹9-11:严禁随意更改其它模块或系统的有关设置和配置。

说明:编程时,不能随心所欲地更改不属于自己模块的有关设置如常量、数组的大小等。

¹9-12:不能随意改变与其它模块的接口。

¹9-13:充分了解系统的接口之后,再使用系统提供的功能。

示例:在B型机的各模块与操作系统的接口函数中,有一个要由各模块负责编写的初始化过程,此过程在软件系统加载完成后,由操作系统发送的初始化消息来调度。因此就涉及到初始化消息的类型与消息发送的顺序问题,特别是消息顺序,若没搞清楚就开始编程,很容易引起严重后果。以下示例引自B型曾出现过的实际代码,其中使用了FID_FETCH_DATA与FID_INITIAL初始化消息类型,注意B型机的系统是在FID_FETCH_DATA之前发送FID_INITIAL的。

 

MIDalarm_module_list[MAX_ALARM_MID];

 

int FARSYS_ALARM_proc( FID function_id, int handle )

{

    _UI i, j;

 

    switch ( function_id )

    {

        ... // program code

   

        case FID_INITAIL:

            for (i = 0; i < MAX_ALARM_MID;i++)

            {

                if (alarm_module_list[i]==BAM_MODULE // **)

                   || (alarm_module_list[i]==LOCAL_MODULE)

                {

 

                    for (j = 0; j <ALARM_CLASS_SUM; j++)

                    {

                        FAR_MALLOC( ... );

                    }

                }

            }

 

            ... // program code

 

            break;

   

        case FID_FETCH_DATA:

 

            ... // program code

 

            Get_Alarm_Module( );  // 初始化alarm_module_list

 

            break;

   

        ... // program code

    }

}

 

由于FID_INITIAL是在FID_FETCH_DATA之前执行的,而初始化alarm_module_list是在FID_FETCH_DATA中进行的,故在FID_INITIAL中(**)处引用alarm_module_list变量时,它还没有被初始化。这是个严重错误。

应如下改正:要么把Get_Alarm_Module函数放在FID_INITIAL中(**)之前;要么就必须考虑(**)处的判断语句是否可以用(不使用alarm_module_list变量的)其它方式替代,或者是否可以取消此判断语句。

¹9-14:编程时,要防止差1错误。

说明:此类错误一般是由于把“<=”误写成“<”或“>=”误写成“>”等造成的,由此引起的后果,很多情况下是很严重的,所以编程时,一定要在这些地方小心。当编完程序后,应对这些操作符进行彻底检查。

¹9-15:要时刻注意易混淆的操作符。当编完程序后,应从头至尾检查一遍这些操作符,以防止拼写错误。

说明:形式相近的操作符最容易引起误用,如C/C++中的“=”与“==”、“|”与“||”、“&”与“&&”等,若拼写错了,编译器不一定能够检查出来。

示例:如把“&”写成“&&”,或反之。

ret_flg =(pmsg->ret_flg & RETURN_MASK); 

被写为:

ret_flg =(pmsg->ret_flg && RETURN_MASK);

 

rpt_flg =(VALID_TASK_NO( taskno ) && DATA_NOT_ZERO( stat_data ));

被写为:

rpt_flg =(VALID_TASK_NO( taskno ) & DATA_NOT_ZERO( stat_data ));

¹9-16:有可能的话,if语句尽量加上else分支,对没有else分支的语句要小心对待;switch语句必须有default分支。

¹9-17:Unix下,多线程的中的子线程退出必需采用主动退出方式,即子线程应return出口。

¹9-18:不要滥用goto语句。

说明:goto语句会破坏程序的结构性,所以除非确实需要,最好不使用goto语句。

½9-1:不使用与硬件或操作系统关系很大的语句,而使用建议的标准语句,以提高软件的可移植性和可重用性。

½9-2:除非为了满足特殊需求,避免使用嵌入式汇编。

说明:程序中嵌入式汇编,一般都对可移植性有较大的影响。

½9-3:精心地构造、划分子模块,并按“接口”部分及“内核”部分合理地组织子模块,以提高“内核”部分的可移植性和可重用性。

说明:对不同产品中的某个功能相同的模块,若能做到其内核部分完全或基本一致,那么无论对产品的测试、维护,还是对以后产品的升级都会有很大帮助。

½9-4:精心构造算法,并对其性能、效率进行测试。

½9-5:对较关键的算法最好使用其它算法来确认。

½9-6:时刻注意表达式是否会上溢、下溢。

示例:如下程序将造成变量下溢。

unsignedchar size ;

while(size-- >= 0) // 将出现下溢

{

    ... // program code

}

 

当size等于0时,再减1不会小于0,而是0xFF,故程序是一个死循环。应如下修改。

char size;// 从unsigned char 改为char

while(size-- >= 0)

{

    ... // program code

}

½9-7:使用变量时要注意其边界值的情况。

示例:如C语言中字符型变量,有效值范围为-128到127。故以下表达式的计算存在一定风险。

char chr =127;

int sum =200;

 

chr += 1; //127为chr的边界值,再加1将使chr上溢到-128,而不是128。

sum +=chr; // 故sum的结果不是328,而是72。

 

若chr与sum为同一种类型,或表达式按如下方式书写,可能会好些。

sum = sum+ chr + 1;

½9-8:留心程序机器码大小(如指令空间大小、数据空间大小、堆栈空间大小等)是否超出系统有关限制。

½9-9:为用户提供良好的接口界面,使用户能较充分地了解系统内部运行状态及有关系统出错情况。

½9-10:系统应具有一定的容错能力,对一些错误事件(如用户误操作等)能进行自动补救。

½9-11:对一些具有危险性的操作代码(如写硬盘、删数据等)要仔细考虑,防止对数据、硬件等的安全构成危害,以提高系统的安全性。

½9-12:使用第三方提供的软件开发工具包或控件时,要注意以下几点:

(1)充分了解应用接口、使用环境及使用时注意事项。

(2)不能过分相信其正确性。

(3)除非必要,不要使用不熟悉的第三方工具包与控件。

说明:使用工具包与控件,可加快程序开发速度,节省时间,但使用之前一定对它有较充分的了解,同时第三方工具包与控件也有可能存在问题。

½9-13:资源文件(多语言版本支持),如果资源是对语言敏感的,应让该资源与源代码文件脱离,具体方法有下面几种:使用单独的资源文件、DLL文件或其它单独的描述文件(如数据库格式)


10 代码编辑、编译、审查

¹10-1:打开编译器的所有告警开关对程序进行编译。

¹10-2:在产品软件(项目组)中,要统一编译开关选项。

¹10-3:通过代码走读及审查方式对代码进行检查。

说明:代码走读主要是对程序的编程风格如注释、命名等以及编程时易出错的内容进行检查,可由开发人员自己或开发人员交叉的方式进行;代码审查主要是对程序实现的功能及程序的稳定性、安全性、可靠性等进行检查及评审,可通过自审、交叉审核或指定部门抽查等方式进行。

¹10-4:测试部测试产品之前,应对代码进行抽查及评审。

½10-1:编写代码时要注意随时保存,并定期备份,防止由于断电、硬盘损坏等原因造成代码丢失。

½10-2:同产品软件(项目组)内,最好使用相同的编辑器,并使用相同的设置选项。

说明:同一项目组最好采用相同的智能语言编辑器,如Muiti Editor,Visual Editor等,并设计、使用一套缩进宏及注释宏等,将缩进等问题交由编辑器处理。

½10-3:要小心地使用编辑器提供的块拷贝功能编程。

说明:当某段代码与另一段代码的处理功能相似时,许多开发人员都用编辑器提供的块拷贝功能来完成这段代码的编写。由于程序功能相近,故所使用的变量、采用的表达式等在功能及命名上可能都很相近,所以使用块拷贝时要注意,除了修改相应的程序外,一定要把使用的每个变量仔细查看一遍,以改成正确的。不应指望编译器能查出所有这种错误,比如当使用的是全局变量时,就有可能使某种错误隐藏下来。

½10-4:合理地设计软件系统目录,方便开发人员使用。

说明:方便、合理的软件系统目录,可提高工作效率。目录构造的原则是方便有关源程序的存储、查询、编译、链接等工作,同时目录中还应具有工作目录----所有的编译、链接等工作应在此目录中进行,工具目录----有关文件编辑器、文件查找等工具可存放在此目录中。

½10-5:某些语句经编译后产生告警,但如果你认为它是正确的,那么应通过某种手段去掉告警信息。

说明:在Borland C/C++中,可用“#pragma warn”来关掉或打开某些告警。

示例:

#pragmawarn -rvl // 关闭告警

intexamples_fun( void )

{

      // 程序,但无return语句。

}

#pragmawarn +rvl // 打开告警

编译函数examples_fun时本应产生“函数应有返回值”告警,但由于关掉了此告警信息显示,所以编译时将不会产生此告警提示。

½10-6:使用代码检查工具(如C语言用PC-Lint)对源程序检查。

½10-7:使用软件工具(如 LogiSCOPE)进行代码审查。


11 代码测试、维护

¹11-1:单元测试要求至少达到语句覆盖。

¹11-2:单元测试开始要跟踪每一条语句,并观察数据流及变量的变化。

¹11-3:清理、整理或优化后的代码要经过审查及测试。

¹11-4:代码版本升级要经过严格测试。

¹11-5:使用工具软件对代码版本进行维护。

¹11-6:正式版本上软件的任何修改都应有详细的文档记录。

½11-1:发现错误立即修改,并且要记录下来。

½11-2:关键的代码在汇编级跟踪。

½11-3:仔细设计并分析测试用例,使测试用例覆盖尽可能多的情况,以提高测试用例的效率。

½11-4:尽可能模拟出程序的各种出错情况,对出错处理代码进行充分的测试。

½11-5:仔细测试代码处理数据、变量的边界情况。

½11-6:保留测试信息,以便分析、总结经验及进行更充分的测试。

½11-7:不应通过“试”来解决问题,应寻找问题的根本原因。

½11-8:对自动消失的错误进行分析,搞清楚错误是如何消失的。

½11-9:修改错误不仅要治表,更要治本。

½11-10:测试时应设法使很少发生的事件经常发生。

½11-11:明确模块或函数处理哪些事件,并使它们经常发生。

½11-12: 坚持在编码阶段就对代码进行彻底的单元测试,不要等以后的测试工作来发现问题。

½11-13:去除代码运行的随机性(如去掉无用的数据、代码及尽可能防止并注意函数中的“内部寄存器”等),让函数运行的结果可预测,并使出现的错误可再现。


12 宏

¹12-1:用宏定义表达式时,要使用完备的括号。

示例:如下定义的宏都存在一定的风险。

#defineRECTANGLE_AREA( a, b ) a * b

#defineRECTANGLE_AREA( a, b ) (a * b)

#defineRECTANGLE_AREA( a, b ) (a) * (b)

正确的定义应为:

#defineRECTANGLE_AREA( a, b ) ((a) * (b))

¹12-2:将宏所定义的多条表达式放在大括号中。

示例:下面的语句只有宏的第一条表达式被执行。为了说明问题,for语句的书写稍不符规范。

#defineINTI_RECT_VALUE( a, b )\

    a = 0;\

    b = 0;

 

for (index= 0; index < RECT_TOTAL_NUM; index++)

    INTI_RECT_VALUE( rect.a, rect.b );

 

正确的用法应为:

#defineINTI_RECT_VALUE( a, b )\

{\

    a = 0;\

    b = 0;\

}

 

for (index= 0; index < RECT_TOTAL_NUM; index++)

{

   INTI_RECT_VALUE( rect[index].a,rect[index].b );

}

¹12-3:使用宏时,不允许参数发生变化。

示例:如下用法可能导致错误。

#defineSQUARE( a ) ((a) * (a))

 

int a = 5;

int b;

b =SQUARE( a++ ); // 结果:a = 7,即执行了两次增1。

 

正确的用法是:

b =SQUARE( a );

a++; // 结果:a = 6,即只执行了一次增1。

_


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 三菱PLC编程是现代工业控制系统常用的方法之一。在实际的工业生产中,PLC编程负责控制各种各样的装置与设备,实现自动化生产的目标。因此,拥有大量的三菱PLC编程实例资源,可以帮助工程师们更好地掌握PLC编程技术,从而提高工作效率,同时也可以保证设备的稳定性与精度。 三菱PLC编程实例资源包含了很多有实际工作经验的工程师们编写的PLC程序,这些程序可以帮助新手工程师们深入了解PLC的使用方法和工作原理,同时也可以让他们学会如何设计和编写灵活、高效的PLC控制程序。 此外,三菱PLC编程实例资源还可以帮助工程师们解决一些常见问题,比如如何在PLC系统中实现数据采集和控制,如何在PLC系统中进行数据处理和传输,如何使用不同类型的传感器和执行器等等。通过学习这些实例资源,工程师们可以更好地掌握PLC编程技巧,提高编程效率和质量。 总之,拥有大量的三菱PLC编程实例资源是非常有益的。这些资源可以帮助工程师们深入学习PLC编程技术,提高工作效率和质量,同时也可以保证设备的稳定性和精度,从而为工业生产带来更大的价值。 ### 回答2: 三菱PLC编程实例资源是指三菱电机PLC编程中的应用实例和资源。PLC编程实例是指根据不同应用场景所设计的PLC程序样例,资源包括了PLC编程相关的软件、驱动、手册等资料。三菱PLC广泛应用于各个行业,如工业自动化、智能交通、建筑控制等领域,因此PLC编程实例资源也非常丰富,部分资源可以从官方网站上获取。 三菱PLC编程实例资源主要有以下特点: 1. 各具特色:不同的行业和场景所需要的PLC编程实例不同,因此三菱PLC编程实例资源也非常具有特色,可以根据需要选择相应的样例进行学习和应用。 2. 高度可定制:PLC编程实例可以根据具体应用场景进行修改和优化,因此特别适合需要定制化需求的客户使用。 3. 丰富多彩:三菱PLC编程实例资源涵盖了从基础到高级的各种应用,可以更好地满足不同学习和应用需求。 通过学习和应用三菱PLC编程实例资源,可以更好地掌握PLC编程技能,进而有效地提升工作效率和产品质量。 ### 回答3: 三菱PLC编程实例资源丰富多样,包括官方手册、编程示例、视频教程、网络课程等。 首先是官方手册,三菱PLC官方手册明确介绍了PLC程序设计的基本规则、语法和常用指令,可以帮助初学者掌握PLC编程的基础知识,进一步了解PLC实现控制的原理和方法。 其次是编程示例,三菱PLC编程示例是基于实际项目开发的,涵盖了多种应用场景和各类功能模块的实现,程序设计规范、代码风格等都是值得学习的范例。 此外还有丰富的视频教程和网络课程,可以通过网络平台访问,帮助不同层次的学习者加深对PLC编程的理解和实践。 总之,三菱PLC编程实例资源齐全,学习者可以从多个渠道获取与实际应用相关的知识和技能,提高PLC以及自动化控制领域的专业水平。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值