标签:出错 nat 脚本 基础 开发 some bre 函数 except
文件名称:C#开发规范
版 本:V2.0
目的是为了规范每个人的编程风格,为确保系统源程序可读性,从而增强系统可维护性,制定下述编程规范,以规范系统各部分编程。系统继承的其它资源中的源程序也应按此规范作相应修改。
规则: 编程时强制必须遵守的原则。建议: 编程时必须加以考虑的原则。格式: 对此规范格式的说明。说明: 对此规范或建议进行必要的解释。示例: 对此规范或建议从正、反两个方面给出例子。
内容包括:排版、命名规则、基本原则、注释、表达式与语句、类与接口, JavaScript 编码过程的排版、命名、声明、注释等等。 自标准公布日起,所有代码都要遵守本标准。在系统的编码、测试及维护过程中,要求严格遵守。
说明:这是编码基础,贯穿整个软件生命周期,只有易读、易维护方便后期软件维护升级,这样的代码才有生命持久力。
说明:保持代码的简洁化是软件工程化的基本要求。除非是底层封闭性开发,否则代码苦涩难懂,就会造成封闭。
说明:编程考虑正确性、可维护性、可扩展性等质量因素,性能考虑要放在重要位置,因为性能时常会影响到正确及可维护。
说明:需求,变更标准规范,可以让我们减少错误出现的频率。(暂时需求文档还未编写)
程序排版的目的是使代码的逻辑更清晰、更易于理解,不仅可以确保系统源程序可读性,而且会涉及到产品质量,涉及到个人能力的提高。
顺序是:using语句、命名空间、注释、类。
说明:以下内容如果某些节不需要,可以忽略。但是其它节要保持该次序。
正例:
using System;
namespace HyBy.xxx
{
/// <summary>
/// 版权所有: 版权所有(C) 2013,华跃博弈
/// 内容摘要: 本类是…..,包括主要……模块、……函数及功能是…….
/// 完成日期: 输入完成日期,例:2013-9-1
/// 版 本:
/// 作 者:
///
/// 修改记录1: 修改历史记录,包括修改日期、修改者及修改内容
/// 修改日期:
/// 版 本 号:
/// 修 改 人:
/// 修改内容:
/// 修改记录2: …
/// </summary>
public class Test
{
}
}
不同类别的using语句之间用空行分隔。
说明: using 中标准的命名空间要在本地的命名空间之前,注意按照字母顺序排列。
正例:
using System; // .Net的
using System.Data;
using OverFlow.Win.Wps; //第三方的
using HyBy.HyB; //程序自身的
说明:(如大括号‘{’和‘}’)应各独占一行并且位于同一列,同时与引用它们的语句左对齐。在函数体的开始、类和接口的定义、以及if、for、do、while、switZH、case 语句中的程序都要采用如上的缩进方式
反例:
for (...) {
... // 程序代码
}
if (...)
{
... // 程序代码
}
void example_fun( void )
{
... // 程序代码
}
正例:
for (...)
{
... // 程序代码
}
if (...)
{
... // 程序代码
}
void example_fun( void )
{
... // 程序代码
}
说明:包括空格在内不超过80列。
尽量代码列宽控制在屏幕宽度以内左右,每行长度尽量避免超过屏幕宽度。
if、else、else if、for、while、do等,执行语句换行。必须加{}。
说明:这样可以防止书写失误,也易于阅读。
反例:
if (varible1 < varible2) varible1 = varible2;
正例:
if(varible1 < varible2)
{
varible1 = varible2;
}
说明:这样便于程序阅读和查找。
正例:
iLength = 10;
iWidth = 5; // 矩形的长与宽关系较密切,放在一起。
StrCaption = “Test”;
反例:
iLength = 10;
strCaption = “Test”;
iWidth = 5;
缩进应该是每行一个Tab(4个空格的距离),不要在代码中使用Tab字符。
说明:消除不同编辑器对TAB处理的差异,有的代码编辑器可以设置用空格代替TAB键。
左花括号 “{”放于关键字或方法名的下一行并与之对齐。{ }之内的代码块使用缩进规则对齐。
说明:这样使代码便于阅读,并且方便注释。
do while语句和结构的类型化时可以例外,while条件和结构名可与 } 在同一行。
正例:
void Function(int iVar)
{ // 独占一行并与引用语句左对齐。
while (condition)
{
TestSomething(); // 与{ }缩进4格
}
}
反例:
void Function(int iVar){
while (condition){
TestSomething();
}}
正例:
tERPTes.wHead = 0;
tERPTes.wTail = wMaxNumOfERP - 1;
tERPTes.wFree =wMaxNumOfERP;
tERPTes.wAddress = wERPAddr;
tERPTes.wSize = wERPSize;
说明:空行是为了将逻辑上相关联的代码分块,以便提高代码的可阅读性。
正例:
voidSpy(void)
{
// Spy实现代码
}
// 空一行
voidLbck(void)
{
// Ack实现代码
}
反例:
voidSpy(void)
{
// Hey实现代码
}
voidLbck (void)
{
// Lbck实现代码
}
//两个逻辑程序块,用空行加以分隔。
一元操作符、++及--与操作数间不需要空格。“[]”、“.”这类操作符前后不加空格。
正例:
!bValue
~iValue
++iCount
&fSum
aiNumber[i]= 5;
tBox.dWidth
正例:
iNumberA +=iNumberB +iNumberC;
说明:if、for、while等关键字之后应留一个空格再跟左括号‘(’,以突出关键字。
正例:在方法名和左括符 “(” 之间不要使用空格,这样有助于辨认代码中的方法调用与关键字。
while凵(true)
说明:函数名后紧跟左括号‘(’,以与关键字区别。
‘(’向后紧跟,‘)’、‘,’、‘;’向前紧跟,紧跟处不留空格。‘,’之后要留空格。‘;’不是行结束符号时其后要留空格。
正例:
for (i = 0; i < MAX_BSC_NUM; i++)
{
TestSomething(iWidth,凵iHeight);
}
正例:
/* 注释内容 */
// 注释内容
反例:
/*注释内容*/
//注释内容
(超过120列)要在低优先级操作符处换行,换行注意要与第一个条件对齐。
说明:
1、在逗号后换行。
2、在低优先级操作符前换行。
3、1优先2
正例:
if ((iFormat == ZH_A_Format_M)
&& (iOfficeType == ZH_BSC_M)) // 条件表达式的续行在第一个条件处对齐
{
TestSomething();
}
for (long_initialization_statement;
long_condiction_statement; // for循环语句续行在初始化条件语句处对齐
long_update_statement)
{
TestSomething();
}
// 函数声明的续行在第一个参数处对齐
BYTE ReportStatusZHeckPara(BYTE ucCallNo,
BYTE ucStatusReportNo);
// 赋值语句的续行应在赋值号处对齐
fTotalTotle = fTotalTotle + faCustomerPurZHases[iID]
+fSalesTax(faCustomerPurZHases[iID]);
正例:
double CalcArea(double dWidth, double dHeight);
反例:
double
CalcArea(double dWidth, double dHeight);
注释是软件可读性的具体体现。程序注释量一般占程序编码量的20%,软件工程要求不少于20%。程序注释不能用抽象的语言,类似于"处理"、"循环"这样的计算机抽象语言,要精确表达出程序的处理说明。避免每行程序都使用注释,可以在一段程序的前面加一段注释,具有明确的处理逻辑。
注释必不可少,但也不应过多,不要被动的为写注释而写注释
代码间多行注释为“/* … */”,单行注释采用“// …”。
正例:
public class Test
{
//数据成员 (单行注释)
private int m_iProperty;
/// <summary>
/// 示例属性
/// </summary>
public int Property
{
get
{
return m_iProperty;
}
/* set( 多行注释)
{
m_iProperty = value;
} */
}
说明:注释的原则是有助于对程序的阅读理解,注释不宜太多也不能太少,注释语言必须准确、易懂、简洁。有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息。
说明:注释使用中文,主要给内部员工使用。
说明:注释必须列出:内容摘要、版本号、作者、完成日期、修改信息等。
正例:
/// <summary>
///版权所有: 版权所有(C) 2013,华跃博弈
///内容摘要: 本类的内容是…..
///完成日期:2013年3月1日
///版 本:V1.1
///作 者:王五
///
///修改记录1:
///修改日期:2013年9月10日
///版 本 号:V1.2
///修 改 人:王五
///修改内容:对方法……进行修改,修正故障BUG……。
///修改记录2:
///修改日期:2013年3月20日
///版 本 号:V1.3
///修 改 人:王五
///修改内容:对方法……进行进一步改进,修正故障……。
/// <summary>
针对(多分支、多重嵌套的条件语句或循环语句)。
说明:此时注释可以用英文,方便查找对应的语句。
正例:
void Main()
{
if (…)
{
…
while (…)
{
…
} /*end of while(…) */ // 指明该条while语句结束
…
} /*end ofif (…) */ // 指明是哪条语句结束
} /* end of void main()*/ // 指明函数的结束
对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开。
说明:在使用缩写时或之前,应对缩写进行必要的说明。
正例:
如下书写比较结构清晰
/* 获得子系统索引 */
iSubSysIndex = aData[iIndex].iSysIndex;
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
反例1:
如下例子注释与描述的代码相隔太远。
/* 获得子系统索引 */
iSubSysIndex = aData[iIndex].iSysIndex;
反例2:
如下例子注释不应放在所描述的代码下面。
iSubSysIndex = aData[iIndex].iSysIndex;
/* 获得子系统索引 */
反例3:
如下例子,显得代码与注释过于紧凑。
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
说明:代码不要过于紧凑
反例:
//注释
程序代码 one //注释
程序代码 two
正例:
//注释
程序代码 one
//注释
程序代码 two
说明:可使程序排版整齐,并方便注释的阅读与理解。
正例:
如下注释结构比较清晰
int TestSomething(void)
{
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
}
反例:
如下例子,排版不整齐,阅读不方便;
int TestSomething(void)
{
/* 代码段1注释 */
[ 代码段1 ]
/* 代码段2注释 */
[ 代码段2 ]
}
说明:这些语句往往是程序实现某一特殊功能的关键,对于维护人员来说,良好的注释有助于更好的理解程序,有时甚至优于看设计文档。
〖建议3-1〗通过对函数或过程、变量、结构等正确的命名以及合理地组织代码结构,使代码成为自注释的。
说明:清晰准确的函数、变量命名,可增加代码的可读性,减少不必要的注释。
〖建议3-2〗尽量避免在注释中使用缩写
说明:注释使用缩写时,应对缩写进行必要的说明。
好的命名规则能极大地增加可读性和可维护性。同时,对于一个有上百个人共同完成的大项目来说,统一命名约定也是一项必不可少的内容。本章对程序中的所有标识符(包括命名空间、变量名、常量名、控件名、参数名、属性名、方法名、类名、接口等)的命名做出约定。
说明:标识符应当直观且可以拼读,程序中的英文单词一般不要太复杂,用词应当准确。
只能由26个英文字母,10个数字,及下划线的一个子集来组成,并严格禁止使用连续的下划线,下划线也不能出现在标识符头或结尾(预编译开关除外)
说明:这样做的目的是为了使程序易读。因为 variable_name 和 variable__name 很难区分,下划线符号‘_’若出现在标识符头或结尾,容易与不带下划线‘_’的标识符混淆。
说明:较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。
正例:
如下单词的缩写能够被大家认可:
temp 可缩写为 tmp ;
flag 可缩写为 flg ;
statistic 可缩写为 stat ;
increment 可缩写为 inc ;
message 可缩写为 msg ;
规定的常用缩写如下:
常用词 | 缩写 |
Argument | Arg |
Buffer | Buf |
Clear | Clr |
Clock | Clk |
Compare | Cmp |
Configuration | Cfg |
Context | Ctx |
Delay | Dly |
Device | Dev |
Disable | Dis |
Display | Disp |
Enable | En |
Error | Err |
Function | Fnct |
Hexadecimal | Hex |
High Priority Task | HPT |
I/O System | IOS |
Initialize | Init |
Mailbox | Mbox |
Manager | Mgr |
Maximum | Max |
Message | Msg |
Minimum | Min |
Multiplex | Mux |
Operating System | OS |
Overflow | Ovf |
Parameter | Param |
Pointer | Ptr |
Previous | Prev |
Priority | Prio |
Read | Rd |
Ready | Rdy |
Register | Reg |
SZHedule | SZHed |
Semaphore | Sem |
Stack | Stk |
SynZHronize | Sync |
Timer | Tmr |
Trigger | Trig |
Write | Wr |
说明:下面是一些在软件中常用的反义词组。
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
正例:
如 DISP_BUF_SIZE、MIN_VALUE、MAX_VALUE 等等。
一般变量名不得取单个字符(如l等)作为变量名,变量名不要过长,局部循环变量除外。
说明:局部变量,如果用单个字符表示,很容易出错(如l写成1),编译时查不出的,则有可能增加排错时间。记得简化变量名称。
说明:变量活动范围前缀规范如下:
m_ : 类的成员变量(属性所对应的变量)
空 : 局部变量不加范围前缀
说明:常用变量类型前缀列表如下:
i :int
f :float
d :double
dcm : decimall
ZH :ZHar
l :long
bt :byte
sbt :sbyte
b :bool
sht :short
usht :ushort
ul :ulong
ar :array
str :string
st :struct
以上前缀可以进一步组合,在进行组合时,数组类型的前缀指示符必须放在变量类型前缀的首位。
变量名的主体应当使用“名词”或者“形容词+名词”,且首字母必须大写。
说明:前缀为变量类型前缀。
用大写字母开头的单词组合而成,应当使用“动词”或者“动词+名词”。
说明:方法名力求清晰、明了,通过方法名就能够判断方法的主要功能。方法名中不同意义字段之间不要用下划线连接,而要把每个字段的首字母大写以示区分。函数命名采用大小写字母结合的形式,但专有名词不受限制。
标识符用点号分隔开,且必须以HyBy开头。
说明:以HyBy开头,随后部分是系统、模块等。
构成类名的每个单词的首字母的首字母也必须大写。在构成类名的单词之间不用下划线。
说明:
1.名字应该能够标识事物的特性。
2. 名字尽量不使用缩写,除非它是众所周知的。
3.名字可以有两个或三个单词组成,但通常不应多于三个。
4.在名字中,所有单词第一个字母大写。
〖建议4-1〗尽量避免名字中出现数字编号,如Value1、Value2等,除非逻辑上的确需要编号。
正例:
intiLevel;
intiSize;
反例:
intiLevel,iSize;
说明:同一变量取值不同时,其代表的意义也不同。
〖建议5-1〗变量声明应该只放在代码段的开始部分。最好不要到使用时才声明变量。对象类变量在函数体结束后,手工设置为null值,以利于资源的回收。
正例:
void Method()
{
int iTest = 0;//方法块的开始
//其它语句
}
表达式是语句的一部分,表达式和语句虽然看起来比较简单,但使用时不小心会造成重大错误,而且不易查觉。正确使用表达式和if、for、while、goto、switZH等基本语句。
说明:复杂的语句阅读起来,难于理解,并容易隐藏错误。变量定义时,一行只定义一个变量。
正例:
int iHelp;
int iBase;
int iResult;
iHelp= iBase;
iResult = iHelp + GetValue(iBase);
反例:
int iBase, iResult; // 一行定义多个变量
iResult = iBase + GetValue(iBase); // 一条语句实现多个功能,iBase有两种用途。
说明:由于将运算符的优先级与结合律熟记是比较困难的,为了防止产生歧义并提高可读性,即使不加括号时运算顺序不会改变,也应当用括号确定表达式的操作顺序。
正例:
if (((iYear % 4 == 0)&& (iYear % 100 != 0)) || (iYear % 400 == 0))
反例:
if (iYear % 4 == 0 && iYear % 100 != 0 || iYear % 400 == 0)
说明:带附加功能的表达式难于阅读和维护,它们常常导致错误。对于一个好的编译器,下面两种情况效果是一样的。
正例:
ariVar[1] = ariVar[2] + ariVar[3];
ariVar[4]++;
iResult = ariVar[1] + ariVar[4];
ariVar[3]++;
反例:
iResult = (ariVar[1] = ariVar[2] + ariVar[3]++) + ++ariVar[4] ;
说明:无论是float还是double类型的变量,都有精度限制。所以一定要避免将浮点变量用“==”或“!=”与数字比较,应该转化成“>=”或“<=”形式。
正例:
if ((fResult >= -EPSINON) && (fResult <= EPSINON))
反例:
if (fResult == 0.0) // 隐含错误的比较
其中EPSINON是允许的误差(即精度)。
每一个case分支必须使用break结尾,最后一个分支必须是default分支。
说明:避免漏掉break语句造成程序错误。同时保持程序简洁。对于多个分支相同处理的情况可以共用一个break,但是要用注释加以说明。
正例:
switZH (iMessage)
{
case SPAN_ON:
[处理语句]
break;
case SPAN_OFF:
[处理语句]
break;
default:
[处理语句]
break;
}
〖建议〗循环嵌套层数不大于3次。
〖建议〗do while语句和while语句仅使用一个条件。
说明:保持程序简洁。如果需要判断的条件较多,建议用临时布尔变量先计算是否满足条件。
正例:
BOOLEAN bCondition;
do
{
……..
bCondition = ((tAp[iPortNo].bStateAcpActivity != PASSIVE)
|| (tAp[iPortNo].bStateLacpActivity != PASSIVE))
&& (abLacpEnabled[iPortNo])
&& (abPortEenabled[iPortNo])
}while (bCondition);
〖建议〗当switZH语句的分支比较多时,采用数据驱动方式。
说明:当switZH语句中case 语句比较多时,会降低程序的效率。
〖建议〗如果循环体内存在逻辑判断 并且循环次数很大,宜将逻辑判断移到循环体的外面。
说明:下面两个示例中,反例比正例多执行了NUM-1次逻辑判断。并且由于前者总要进行逻辑判断,使得编译器不能对循环进行优化处理,降低了效率。如果NUM非常大,最好采用正例的写法,可以提高效率。
const int NUM=1000;
正例:
if (bCondition)
{
for (i = 0; i < NUM; i++)
{
TestSomething();
}
}
else
{
for (i = 0; i < NUM; i++)
{
TestOtherthing();
}
}
反例:
for (i = 0; i < NUM; i++)
{
if (bCondition)
{
TestSomething();
}
else
{
TestOtherthing();
}
}
〖建议〗for语句的循环控制变量的取值采用“半开半闭区间”写法。
正例:
int aiScore[NUM];
…
for (i = 0; i < NUM; i++)
{
printf(“%d\n”,aiScore[i])
}
反例:
int aiScore[NUM];
…
for (i = 0; i <= NUM-1;i++)
{
printf(“%d\n”,aiScore[i]);
}
相比之下,正例的写法更加直观,尽管两者的功能是相同的。
正例:
public class Test
{
private int m_iProperty; //数据成员
public int Property //属性
{
get
{
return m_iProperty;
}
set
{
m_iProperty = value;
}
}
public Test() //构造函数
{
}
public string Operation1(long lParam1, string strParam2) //方法
{
return null;
}
}
〖建议7-1〗功能相关的方法放在一起。
说明:如接口中关系较紧密的的几个方法,类属性的get和set 方法,有调用关系的方法,重载的方法等有相近或相关的方法尽可能放在一起,方便阅读。
说明:过多的函数参数会导致性能降低。
正例:
return booleanExp;
反例:
if (booleanExp)
{
return true;
}
else
{
return false;
}
说明:
格式化包含单个public类的C#源文件。接口格式化与之类似,
using System;
namespaceHyBy.xxx
{
/// <summary>
///版权所有(C)2013,华跃博弈
///内容摘要: 本文件的内容是…..,包括主要……模块、……函数及功能是…….
/// 完成日期:2013年3月1日
///版 本:V1.0
///作 者:王五
///
///修改记录1:
///修改日期:2013年3月10日
///版 本 号:V1.3
///修 改 人:王五
///修改内容:对方法……进行修改,修正故障BUG。
///修改记录2:
///修改日期:2013年3月20日
///版 本 号:V1.3
///修 改 人:王五
///修改内容:对方法……进行进一步改进,修正故障……。
/// <summary>
publicclass Test
{
//数据成员
privateint m_iProperty;
/// <summary>
///示例属性
/// <summary>
publicint Property
{
get
{
return m_iProperty;
}
set
{
m_iProperty = value;
}
}
/// <summary>
///示例方法
/// <summary>
///参数1
///参数2
///返回值
publicstring Operation1(long Param1, string Param2)
{
returnnull;
}
}
}
说明:必须在方法的注释中标明,对于所调用的其他方法所抛出的异常,选择主要的在注释中说明。对于非RuntimeException ,即throws子句声明
会抛出的异常,必须在方法的注释中标明。说明:异常注释用@exception或@throws表示,但推荐用@exception标注Runtime 异常,@throws标注非Runtime 异常。异常的注释必须说明该异常的含义及什么条件下抛出该异常。
JavaScript 程序应该尽量放在 .js 的文件中,需要调用的时候在 页面文件 中以 <script src="jstest.js"> 的形式包含进来。
JavaScript 代码如果不是该页面文件专用,则应尽量避免在页面文件中直接编写 JavaScript 代码。这样会增加 页面 文件的容量,影响代码的压缩和缓存的使用及加载速度。
说明:每行代码应小于 80 个字符。如果代码较长,应尽量选择换行,下一行代码应缩进 4个空格(此处跟C#规范相同不能用Tab键 一个Tab用4个空格代替)。
说明:换行应选择在操作符和标点符号之后,最好是在逗号‘,‘之后,而不要在变量名、字符串、数字、或‘)‘ ‘]‘ ‘++‘ ‘--‘等符号之后换行
<script language="javascript">
var valueA = 1;
反例
var valueB = valueA
+1;
正例
var valueC = valueB +
valueA;
alert(valueB);
alert(valueC);
</script>
说明:JavaScript 中的标识符的命名规则:
•以字母、下划线‘_‘或美元符号‘$‘开头
•允许名称中包含字母,数字,下划线‘_‘和美元符号‘$‘
•区分大小写
变量、参数、成员变量、函数等名称均以小写字母开头,构造器的名称以大写字母开头。下划线‘_‘开头的变量一般习惯于标识私有 / 局部成员。而美元符号‘$‘开头的变量习惯于标识系统相关,比如系统进程等。应避免用下划线‘_‘或美元符号‘$‘来命名标识符。尽可能地降低代码的阅读难度。
命名的规范化,有助于编程模式的规范化。
以功能动词的英文命名函数,以其名词命名变量
说明:防止变量复制时出现错误,这是因为 JavaScript 中只有函数的 {} 表明作用域,用 var 关键字声明的局部变量只在函数内有效,而未经 var 声明的变量则被视为全局变量。
正例:
Var iHelp;
Var iLose;
反例:
Var iHelp,iLose
函数名紧接左括号‘(‘之间,而右括号‘)‘和后面的‘{‘之间要有个空格
若函数为匿名 / 无名函数,则 function 关键字和左括号‘(‘之间要留空格,否则可能误认为该函数的函数名为 function
/*------------------------------------------------------------------
*
* 编写日期:
* 功能 模块 用途
* 作者:
* 脚本名称:
*
---------------------------------------------------------------------*/
说明:
<script language="javascript">
//定义全局变量正例
var valueA = 0; // valueA赋值0反例
var valueB = 1;
//执行完f1方法 等待50秒正例
setTimeout(f1,50000);
</script>
说明:
<script type="text/javascript" src="js/login-min.js"></script>
<script type="text/javascript" src="js/login-min.js"></script>
说明:一行结束必须加上分号
说明:表达式和 return 放在同一行,return 关键字后若没有返回表达式,则返回 undefined
正例:
Function funCel()
{
Return a+b;
}
正例:
Function funCel()
{
Return
a+b;
}
说明:HTML 4.01 中的 doctype 需要对 DTD 进行引用,因为 HTML 4.01 基于 SGML。而 HTML 5 不基于 SGML,因此不需要对 DTD 进行引用,但是需要 doctype 来规范浏览器的行为(让浏览器按照它们应该的方式来运行。)。
正例:
<!DOCTYPE HTML>
标签:出错 nat 脚本 基础 开发 some bre 函数 except
原文地址:https://www.cnblogs.com/zhanfuzhi/p/zhan1.html