Jac*_*539 48 c# c++ conventions
我最近在高调代码中已经看过几次,其中常量值被定义为变量,以值命名,然后仅使用一次.我想知道它为什么要完成?
例如Linux Source(resize.c)
unsigned five = 5;
unsigned seven = 7;
Run Code Online (Sandbox Code Playgroud)
例如C#.NET Source(Quaternion.cs)
double zero = 0;
double one = 1;
Run Code Online (Sandbox Code Playgroud)
MrZ*_*bra 83
命名数字是一种可怕的做法,总有一天需要改变,你最终会得到unsigned five = 7
.
如果它有一些含义,请给它一个有意义的名字."神奇数字" five
并没有超过魔法数字5
,它更糟糕,因为它可能实际上并不相同5
.
这种事情通常源于一些货物崇拜风格的编程风格指导,其中有人听说"魔术数字是坏的"并禁止他们使用而没有完全理解为什么.
Ric*_*gle 48
为变量赋予适当的名称可以大大澄清代码,例如
constant int MAXIMUM_PRESSURE_VALUE=2;
Run Code Online (Sandbox Code Playgroud)
这有两个关键优势:
该值MAXIMUM_PRESSURE_VALUE
可以在许多不同的地方使用,如果由于任何原因值变化,您只需要在一个地方更改它.
在使用它时,它会立即显示函数正在执行的操作,例如,下面的代码显然会检查压力是否非常高:
if (pressure>MAXIMUM_PRESSURE_VALUE){
//without me telling you you can guess there'll be some safety protection in here
}
Run Code Online (Sandbox Code Playgroud)然而,一切都有一个反驳论点,你所展示的内容看起来非常像是一个好主意,到目前为止它没有任何意义.定义TWO
为2不会添加任何值
constant int TWO=2;
Run Code Online (Sandbox Code Playgroud)
TWO
可以在许多不同的地方使用,也许可以加倍,也许是为了访问索引.如果将来你需要更改索引,你不能改变,int TWO=3;
因为这会影响你使用TWO的所有其他(完全不相关)的方式,现在你将三倍而不是加倍等如果使用它,它不会给你提供比你刚使用"2"更多的信息.比较以下两段代码:
if (pressure>2){
//2 might be good, I have no idea what happens here
}
Run Code Online (Sandbox Code Playgroud)
要么
if (pressure>TWO){
//TWO means 2, 2 might be good, I still have no idea what happens here
}
Run Code Online (Sandbox Code Playgroud)更糟糕的是(这里似乎是这种情况)TWO
可能不等于2,如果是这样,这是一种混淆形式,其目的是使代码不那么清晰:显然它实现了这一点.
通常的原因是编码标准禁止幻数,但不算TWO
作幻数; 这当然是!99%的时间你想要使用一个有意义的变量名称,但是在1%的时间里使用TWO
而不是2
获得任何东西(抱歉,我的意思是ZERO
).
此代码的灵感来自Java,但旨在与语言无关
Ale*_*x P 30
精简版:
five
只保持数字5的常数是无用的.不要无缘无故地去做这些(有时你必须因为语法或打字规则).这个很容易.
就在这之后:
double zero = 0;
double one = 1;
Run Code Online (Sandbox Code Playgroud)
代码执行此操作:
return zero.GetHashCode() ^ one.GetHashCode();
Run Code Online (Sandbox Code Playgroud)
没有局部变量,替代方案是什么样的?
return 0.0.GetHashCode() ^ 1.0.GetHashCode(); // doubles, not ints!
Run Code Online (Sandbox Code Playgroud)
真是一团糟!可读性绝对是在这里创建本地人的一面.此外,我认为明确地命名变量表明"我们仔细考虑过这一点"比仅仅编写一个令人困惑的返回语句更清楚.
在ext4/resize.c的情况下,这些数字实际上根本不是常量.如果您遵循代码,您将看到它们是计数器,它们的值实际上会在while循环的多次迭代中发生变化.
unsigned three = 1;
unsigned five = 5;
unsigned seven = 7;
Run Code Online (Sandbox Code Playgroud)
三等于一,是吗?那是什么意思?
看,实际发生的是update_backups
通过引用函数传递这些变量ext4_list_backups
:
/*
* Iterate through the groups which hold BACKUP superblock/GDT copies in an
* ext4 filesystem. The counters should be initialized to 1, 5, and 7 before
* calling this for the first time. In a sparse filesystem it will be the
* sequence of powers of 3, 5, and 7: 1, 3, 5, 7, 9, 25, 27, 49, 81, ...
* For a non-sparse filesystem it will be every group: 1, 2, 3, 4, ...
*/
static unsigned ext4_list_backups(struct super_block *sb, unsigned *three,
unsigned *five, unsigned *seven)
Run Code Online (Sandbox Code Playgroud)
它们是在多个呼叫过程中保留的计数器.如果你看一下函数体,你会看到它正在调整计数器以找到下一个3,5或7的幂,创建你在评论中看到的序列:1,3,5,7,9,25 ,27,&c.
现在,对于最奇怪的部分:变量three
初始化为1,因为3 0 = 1.但是,功率0是一种特殊情况,因为它是唯一的时间3 x = 5 x = 7 x.您可以尝试重写ext4_list_backups
与初始值1的所有三个计数器(3上班0,5 0,7 0),你会看到代码多少变得繁琐.有时,在评论中告诉调用者做一些时髦的事情(将列表初始化为1,5,7)更容易.
five = 5
编码风格是不是很好?对于变量five
在resize.c中表示的东西,"five"是一个好名字吗?在我看来,这不是你应该在任何随机项目中模仿的风格.简单名称five
与变量的用途无关.如果您正在处理Web应用程序或快速原型化视频聊天客户端或某些事情并决定命名变量five
,那么您可能会为需要维护和修改代码的任何其他人制造麻烦和烦恼.
然而,这是关于编程的一般性没有描绘出全貌的一个例子.看一下内核的编码风格文档,特别是关于命名的章节.
GLOBAL变量(仅在您确实需要它们时使用)需要具有描述性名称,全局函数也是如此.如果你有一个统计的活跃用户数的函数,你应该叫为"count_active_user()"或类似的,你应该不会把它称为"cntusr()".
...
LOCAL变量名称应该简短,并且要点.如果你有一些随机整数循环计数器,它应该被称为"i".如果没有机会被误解,那么称它为"loop_counter"是非生产性的.类似地,"tmp"可以是用于保存临时值的任何类型的变量.
如果你害怕混淆你的本地变量名,你还有另一个问题,就是所谓的功能 - 生长 - 激素 - 失衡综合症.见第6章(功能).
部分原因是C风格的编码传统.其中一部分是有目的的社会工程.很多内核代码都是敏感的东西,经过多次修改和测试.由于Linux是一个很大的开源项目,它并没有真正伤害到贡献 - 在大多数情况下,更大的挑战是检查这些贡献的质量.
调用该变量five
而不是类似的东西nextPowerOfFive
是一种阻止贡献者干涉他们不理解的代码的方法.在您尝试进行任何更改之前,这是一种尝试迫使您逐行详细阅读您正在修改的代码.
内核维护者是否做出了正确的决定?我不能说.但这显然是一个有目的的举动.
Jos*_*ron 11
我的组织有一些编程指南,其中一个是魔术数字的使用......
例如:
if (input == 3) //3 what? Elephants?....3 really is the magic number here...
Run Code Online (Sandbox Code Playgroud)
这将改为:
#define INPUT_1_VOLTAGE_THRESHOLD 3u
if (input == INPUT_1_VOLTAGE_THRESHOLD) //Not elephants :(
Run Code Online (Sandbox Code Playgroud)
我们还有一个源文件,其格式为-200,000 - > 200,000 #defined:
#define MINUS_TWO_ZERO_ZERO_ZERO_ZERO_ZERO -200000
Run Code Online (Sandbox Code Playgroud)
可用于代替幻数,例如在引用数组的特定索引时.
我想这已经为"可读性"做了.
小智 7
数字0,1,...是整数.这里,'命名变量'给整数赋予不同的类型.指定这些常量可能更合理(const unsigned five = 5;)
我曾经使用类似于几次的东西来为文件写入值:
const int32_t zero = 0 ;
fwrite( &zero, sizeof(zero), 1, myfile );
Run Code Online (Sandbox Code Playgroud)
fwrite接受一个const指针,但是如果某个函数需要一个非const指针,你最终会使用一个非const变量.
PS:这总让我想知道什么可能是零的大小.
你是如何得出它只使用一次的结论?它是公开的,可以在任何组件中使用任意次数.
public static readonly Quaternion Zero = new Quaternion();
public static readonly Quaternion One = new Quaternion(1.0f, 1.0f, 1.0f, 1.0f);
Run Code Online (Sandbox Code Playgroud)
同样的事情适用于.Net框架decimal
类.这也暴露了这样的公共常量.
public const decimal One = 1m;
public const decimal Zero = 0m;
Run Code Online (Sandbox Code Playgroud)
当这些数字具有特殊含义时,数字通常会被赋予名称.
例如,在四元数情况下,标识四元数和单位长度四元数具有特殊含义,并且经常在特殊上下文中使用.即具有(0,0,0,1)的四元数是一个单位四元数,因此通常的做法是定义它们而不是使用幻数.
例如
// define as static
static Quaternion Identity = new Quaternion(0,0,0,1);
Quaternion Q1 = Quaternion.Identity;
//or
if ( Q1.Length == Unit ) // not considering floating point error
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
2865 次 |
最近记录: |