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

推荐订阅源

量子位
T
The Blog of Author Tim Ferriss
U
Unit 42
Microsoft Security Blog
Microsoft Security Blog
WordPress大学
WordPress大学
Vercel News
Vercel News
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
D
DataBreaches.Net
The GitHub Blog
The GitHub Blog
大猫的无限游戏
大猫的无限游戏
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
I
InfoQ
Y
Y Combinator Blog
F
Full Disclosure
B
Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
G
Google Developers Blog
博客园_首页
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
月光博客
月光博客
博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗
S
SegmentFault 最新的问题
腾讯CDC
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
Apple Machine Learning Research
Apple Machine Learning Research
人人都是产品经理
人人都是产品经理
Recent Commits to openclaw:main
Recent Commits to openclaw:main
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Microsoft Azure Blog
Microsoft Azure Blog
云风的 BLOG
云风的 BLOG
Last Week in AI
Last Week in AI
F
Fortinet All Blogs
C
CXSECURITY Database RSS Feed - CXSecurity.com
Hugging Face - Blog
Hugging Face - Blog
T
Threatpost
GbyAI
GbyAI
G
GRAHAM CLULEY
L
Lohrmann on Cybersecurity
T
The Exploit Database - CXSecurity.com
P
Palo Alto Networks Blog
L
LangChain Blog
T
Tenable Blog
C
Cisco Blogs
T
Threat Research - Cisco Blogs
Google Online Security Blog
Google Online Security Blog

Keyle's Blog

公司搬家 | Keyle's Blog 听闻的一些故事 | Keyle's Blog 《恶魔轮盘改》项目完整实现详解:架构、流程与双端同步 | Keyle's Blog .net core服务发布经验总结 | Keyle's Blog 凌晨一点的键盘声 | Keyle's Blog 南京游记 | Keyle's Blog 从老活到小 | Keyle's Blog 一代人有一代人的龙虾要养 | Keyle's Blog 在咖啡凉透前救回了博客数据 | Keyle's Blog 时间的参照物 | Keyle's Blog 沈阳游记 | Keyle's Blog 近况二三则 | Keyle's Blog 阳澄湖游记 | Keyle's Blog 欢乐谷游记 | Keyle's Blog 殊途同归的“搜打撤” | Keyle's Blog 中班学习规划 | Keyle's Blog 桐庐三日游 | Keyle's Blog 9月15日起,租房新规正式实施!居住安全、费用明细、租金调整与权益保障全面解读 | Keyle's Blog 游泳与羽毛球 | Keyle's Blog 8月生活碎片 | Keyle's Blog 卡坦岛桌游玩法 | Keyle's Blog 当时间戳“捣乱”时,互联网会发生什么? | Keyle's Blog 该如何去度过一生 | Keyle's Blog 在Lua中循环Require是如何处理的? | Keyle's Blog
补码陷阱 | Keyle's Blog
2025-10-22 · via Keyle's Blog

为什么这个Bug如此狡猾?

直觉背叛:我们直觉上认为 -A 就是 “负的A”,但在位运算中它变成了”A的补码”
测试遗漏:我们测试了正数情况,但对负数的测试不够充分
认知偏差:我们都”知道”补码,但真正用到时却忘了它的存在

你发现下面代码中的问题了吗 ?

1
2
3
4
5
6
7
8
9

bool ShouldSelect(int value, int mask)
{
if (-value & mask == Mathf.Abs(-value))
{
return -value > 0;
}
return false;
}

在C#中,A & B-A & B 的区别主要在于对负数处理的不同。让我通过具体案例来说明:

案例演示

1
2
3
4
5
6
7
8
9
10
int A = 5;    
int B = 3;


int result1 = A & B;
Console.WriteLine($"A & B = {result1}");


int result2 = -A & B;
Console.WriteLine($"-A & B = {result2}");

二进制分析:

1
2
3
4
5
6
7
A = 5:  0000 0101
B = 3: 0000 0011
A & B: 0000 0001 = 1

-A = -5: 1111 1011 (补码表示)
B = 3: 0000 0011
-A & B: 0000 0011 = 3

更多案例

1
2
3
4
5
6
7
8
9
10
11
12

int A2 = 10;
int B2 = 6;

Console.WriteLine($"{A2} & {B2} = {A2 & B2}");
Console.WriteLine($"-{A2} & {B2} = {-A2 & B2}");


int A3 = -3;
int B3 = -5;

Console.WriteLine($"{A3} & {B3} = {A3 & B3}");

背后的意义

1. 补码表示法

  • 在C#中,整数使用二进制补码表示
  • 正数的补码是其本身
  • 负数的补码 = 对应正数的二进制取反 + 1

2. 运算本质

  • A & B:对两个数的实际二进制位进行按位与
  • -A & B:先计算A的补码(得到-A),再与B进行按位与

3. 实际应用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

[Flags]
enum Permissions
{
Read = 1,
Write = 2,
Execute = 4
}


Permissions userPermissions = Permissions.Read | Permissions.Write;


bool canRead = (userPermissions & Permissions.Read) != 0;


bool wrongCheck = (-(int)userPermissions & (int)Permissions.Read) != 0;

4. 重要注意事项

1
2
3
4

int A = 5, B = 3;
Console.WriteLine($"-A & B = {-A & B}");
Console.WriteLine($"-(A & B) = {-(A & B)}");

总结

  • A & B 是直接的按位与运算,结果可预测
  • -A & B 涉及补码转换,结果取决于负数的二进制表示
  • 在实际编程中,应避免对负数进行无意义的位运算,除非明确理解补码机制
  • 位运算通常用于标志位、掩码操作等场景,应保持操作数的明确性和可读性

本文标题:补码陷阱

文章作者:Keyle

发布时间:2025-10-22

最后更新:2025-10-22

原始链接:https://vrast.cn/posts/55376/

版权声明:©Keyle's Blog. 本站采用署名-非商业性使用-相同方式共享 4.0 国际进行许可