惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Attack and Defense Labs
Attack and Defense Labs
T
Threatpost
C
Cybersecurity and Infrastructure Security Agency CISA
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
Intezer
C
Cyber Attacks, Cyber Crime and Cyber Security
The Register - Security
The Register - Security
量子位
Security Latest
Security Latest
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
小众软件
小众软件
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
C
CXSECURITY Database RSS Feed - CXSecurity.com
MyScale Blog
MyScale Blog
J
Java Code Geeks
Apple Machine Learning Research
Apple Machine Learning Research
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
Spread Privacy
Spread Privacy
Jina AI
Jina AI
博客园 - 【当耐特】
P
Palo Alto Networks Blog
Last Week in AI
Last Week in AI
SecWiki News
SecWiki News
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
G
GRAHAM CLULEY
宝玉的分享
宝玉的分享
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
The Blog of Author Tim Ferriss
V
Vulnerabilities – Threatpost
有赞技术团队
有赞技术团队
T
Tor Project blog
H
Hacker News: Front Page
A
Arctic Wolf
NISL@THU
NISL@THU
A
About on SuperTechFans
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
V
V2EX
N
News and Events Feed by Topic
Webroot Blog
Webroot Blog
Know Your Adversary
Know Your Adversary
P
Privacy International News Feed
I
InfoQ
D
Docker
L
LINUX DO - 最新话题
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
U
Unit 42

博客园 - double64

C++ 安全的拷贝赋值(Copy-and-Swap 惯用法) C++ 基类派生类的 static_cast 和 dynamic_cast 转换的简单测试 visual studio 的 snippet 代码片段模板样式 Windows 右键管理官方小程序Autoruns std::unique_ptr 当删除器类型为 无状态的时构造可以不用传删除器示例 两个用来写 CLI - Command-Line Interface 的命令解析库 enum class 类型转换 int 微软输入法中如何输出当前时间 音程知识 C++ 模板引用参数的各种情况 英语 12 种时态 Qt 手动添加 Q_OBJECT 需要添加的地方 C# WPF 绑定 ObservableObject 实现 INotifyPropertyChanged 接口 C++ 标准库 copy_if C++ lambda 和 bind 何时优先使用 Windows 下的 Qt 中 min max 函数冲突 C++ RVO 或 NRVO 可能触发的条件 C++ std::unique_ptr 和 std::shared_ptr 都支持自定义删除器(deleter) C++ 智能指针和动态数组 std::vector 插入另一个 vector 的范围元素 Qt tableWidget QTableWidget 常用一些属性设置 C++ 内部类(嵌套类)是可以访问外部类的私有保护成员的 C++ 宏展开顺序 C++ std::round() 四舍五入 cv::Mat 和 HalconCpp::HImage 生成和保存图像简单测试 简单易用的图像库:stb_image Halcon HImage 与 Qt QImage 的相互转换
C++ 结合 enum 按位与或组合检测枚举项
double64 · 2026-05-14 · via 博客园 - double64

from deepseek.


在C++中,使用 &(按位与)|(按位或) 来组合和检测枚举项,是处理标志位(flag)的标准做法。

这种用法通常是为枚举的每个成员赋予一个不同的二进制位(即1、2、4、8...),然后通过按位或(|)来组合它们,通过按位与(&)来检测某个位是否被设置。


1. 定义可组合的枚举

通常称为“位掩码”(Bitmask)枚举。关键是每个枚举值必须是2的幂,这样才能保证它们组合时不会互相重叠。

#include <iostream>

// 方法一:C++11 之前的标准做法
enum TextFormat {
    BOLD       = 1 << 0,  // 1
    ITALIC     = 1 << 1,  // 2
    UNDERLINE  = 1 << 2,  // 4
    STRIKETH   = 1 << 3   // 8
};

// 方法二:C++11 推荐的 `enum class`(强类型)
// 需要为它重载 | 和 & 运算符才能在逻辑判断中使用
enum class FileMode : int {
    READ   = 1 << 0,
    WRITE  = 1 << 1,
    APPEND = 1 << 2,
    BINARY = 1 << 3
};

// 为了 enum class 方便使用,重载位运算符
inline FileMode operator|(FileMode a, FileMode b) {
    return static_cast<FileMode>(static_cast<int>(a) | static_cast<int>(b));
}

inline bool operator&(FileMode a, FileMode b) {
    return (static_cast<int>(a) & static_cast<int>(b)) != 0;
}

2. 组合标志(使用 | 按位或)

你可以将多个标志组合成一个值,代表多种属性的集合。

int main() {
    // ---- 使用传统 enum ----
    int style = BOLD | UNDERLINE | ITALIC;
    // style 的二进制: 1 | 4 | 2 = 7

    // 判断是否包含某个标志(使用 & 按位与)
    if (style & BOLD) {
        std::cout << "文本是加粗的" << std::endl;
    }
    if (style & STRIKETH) {
        std::cout << "文本有删除线" << std::endl;  // 不会执行
    }

    // ---- 使用 enum class ----
    FileMode mode = FileMode::READ | FileMode::WRITE | FileMode::APPEND;
    if (mode & FileMode::WRITE) {
        std::cout << "文件可以写入" << std::endl;
    }

    return 0;
}

3. 常用操作模式

操作 代码示例 说明
设置标志 flags = READ | WRITE; 初始化时用 | 组合
添加标志 flags = flags | APPEND;
flags |= APPEND;
在不影响已有标志的情况下增加新标志
移除标志 flags = flags & ~APPEND;
flags &= ~APPEND;
~ 是取反运算符,将APPEND位变为0
检查标志 if (flags & APPEND) 只要包含该标志,结果为非零(true)
切换标志 flags = flags ^ APPEND;
flags ^= APPEND;
^ 是异或,有则移除,无则添加
精确判断 if ((flags & (READ | WRITE)) == (READ | WRITE)) 判断是否同时包含多个标志

4. 完整的使用示例(函数参数)

这是最经典的场景:用一个整数参数接收多种配置选项。

#include <iostream>
#include <string>

enum LogOption {
    LOG_NONE    = 0,
    LOG_ERROR   = 1 << 0,  // 1
    LOG_WARNING = 1 << 1,  // 2
    LOG_INFO    = 1 << 2,  // 4
    LOG_DEBUG   = 1 << 3   // 8
};

void logMessage(const std::string& msg, int options) {
    if (options & LOG_ERROR)   std::cout << "[ERROR] ";
    if (options & LOG_WARNING) std::cout << "[WARNING] ";
    if (options & LOG_INFO)    std::cout << "[INFO] ";
    if (options & LOG_DEBUG)   std::cout << "[DEBUG] ";
    std::cout << msg << std::endl;
}

int main() {
    // 只输出错误和警告
    logMessage("Connection failed", LOG_ERROR | LOG_WARNING);
    
    // 输出所有信息
    logMessage("System started", LOG_ERROR | LOG_WARNING | LOG_INFO | LOG_DEBUG);
    
    return 0;
}

⚠️ 关键注意事项

注意事项 说明
枚举值必须是 2 的幂 这样每个标志对应独立的位,组合时才不会相互干扰
结果是非零表示 true if (flags & FLAG) 是标准写法,不要写成 if ((flags & FLAG) == FLAG),后者只在检查单个标志时等价,但前者更高效
enum class 需要运算符重载 传统 enum 会自动提升为 int,可以直接做位运算;enum class 需要手动重载
负数位运算可能有问题 确保枚举值是正数,不要让最高位变成符号位

💡 总结

符号 用途 典型场景
| 组合多个标志 flags = READ | WRITE;
& 检查是否包含某个标志 if (flags & WRITE)
|= 添加标志 flags |= APPEND;
&= 移除标志 flags &= ~APPEND;
^= 切换标志 flags ^= APPEND;

这种位掩码模式在 Windows API(如 MessageBox 的按钮组合)、Qt 的 setWindowFlags() 等大量库中被广泛使用,是 C/C++ 中处理多选项的标准模式。