使用匿名结构体指针作为常量来杜绝魔数,是否合理/值得?

11 小时 0 分钟前
 liuidetmks

在项目中,用匿名结构体的地址作为常量来标识不同业务类型(例如 A 、B 、C 、D……),

这样做的目的是彻底避免魔术数字( magic number ),并且希望在逻辑判断中直接通过指针比较。

代码 h 文件

typedef struct __BizType *BizTypeRef;

// 对外暴露的常量声明
extern const BizTypeRef kBizTypeA;
extern const BizTypeRef kBizTypeB;
extern const BizTypeRef kBizTypeC;
extern const BizTypeRef kBizTypeD;

实现文件


// 定义结构体
struct __BizType {
    int value;
};

// 定义常量指针
const BizTypeRef kBizTypeA = &(const struct __BizType){ .value = 1 };
const BizTypeRef kBizTypeB = &(const struct __BizType){ .value = 2 };
const BizTypeRef kBizTypeC = &(const struct __BizType){ .value = 3 };
const BizTypeRef kBizTypeD = &(const struct __BizType){ .value = 4 };

使用

// 使用示例
void handleBiz(BizTypeRef type) {
    if (type == kBizTypeA) {
        // 处理业务 A
    } else if (type == kBizTypeB) {
        // 处理业务 B
    }
}
770 次点击
所在节点    程序员
14 条回复
r6cb
10 小时 52 分钟前
为什么不用枚举?
liuidetmks
10 小时 48 分钟前
@r6cb 枚举还是数字啊,还是能使用 1 当做参数传入。 我想完全只使用定义的这几个变量,政出一门
aprikyblue
10 小时 5 分钟前
你看看 enum class
cwxiaos
9 小时 52 分钟前
或许可以叫做更安全的枚举,限制下游代码乱搞
minamo
9 小时 52 分钟前
如果你真这么讨厌魔数,倒也不是不行,但我觉得不值得
iOCZS
9 小时 44 分钟前
本该在语法层解决的问题,在用户侧试图解决,会引入复杂性
ysc3839
9 小时 25 分钟前
这么写的话进行比较时可能并不是直接比较常量,而是要从全局变量里读取值,降低性能。
而且实现文件里这么取临时对象的地址,不怕编译器把这四个对象都优化成使用同一空间?不怕去到悬垂指针出现什么 UB ?
需要枚举类型的地方,能直接传递整数,是 C 允许隐式转换的问题,建议想办法调整编译参数,禁止这种行为,或者迁移到更严格的 C++。
xuanbg
9 小时 9 分钟前
魔数有什么问题吗?其实魔数一点问题都没有,你先定义一个常量,无非就是脱裤子放屁——多此一举
metalvest
8 小时 20 分钟前
为什么不直接用 std::type_index
liuidetmks
7 小时 8 分钟前
@metalvest c


@ysc3839 全局作用域不会 ub 吧
比较的话是比较两个指针地址,性能不存在问题的

@xuanbg 有时候业务变化了,魔数可能哪里弄漏了,这里把结构体匿名,提供一个统一构造方法,方便处理一点。

@aprikyblue c
kneep
6 小时 16 分钟前
@liuidetmks @ysc3839 可能是在说全局指针地址的读取可能会多产生一条指令,而常量通常不需要。应该不是在说你比较了指针指向的内容。
ysc3839
5 小时 46 分钟前
@liuidetmks 地址数值是存在全局变量里的,要先读全局变量,再比较数值
geelaw
1 小时 32 分钟前
@aprikyblue #3 楼主写的是 C 不是 C++,没有 enum class 。(当然,换成 C++ 似乎是比较好的选择。)这一点可以从这段代码可以编译知道(见下面第二点)。

————

几个可以挑剔的点:

一双下划线是保留标识符。

二是初始化的时候 constness 不合适,注意 const BizTypeRef 是 struct __BizType * const 而不是 struct __BizType const *,于是这里会丢失 const ,如果实现方(很容易无意间)尝试修改只读复合字面量的 .value 的话会有 UB 。

三是,如果实现方不需要数据,那么实际上没有必要使用 value ,用 non-const 复合字面量本身就可以确保几个表达式的对象不占据相同的位置(但是 const 复合字面量可能会是同一个对象)。

————

@ysc3839 #7 楼主的版本有不同的值,所以无法是同一个位置。在文件作用域的复合字面量是静态存储期。
cybort
1 小时 19 分钟前
代码静态扫描能解决的问题,为什么要通过编码解决?

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/1164518

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX