在某个论坛上发现了三年前的有趣话题, 哈哈哈哈哈哈, 希望它们看过"数据结构"教科书,也许它们上学时有这本, 也许它们至今还珍藏并且从未看过
我觉得这话题, 的确会有一部分人会理解, 但是我希望给不理解的那部分人看的, 也许这问题本身就很粗浅, 但是我们都高估了计算机专业科班出身的那群孩子的专业知识
error_reporting(E_ALL & ~E_NOTICE);
error_reporting(E_ALL ^ E_NOTICE);
要理解这个问题, 得从位运算的基础说起
PHP中, 整形为32个位, 换句话说,
1 = 00000000000000000000000000000001~1 = 11111111111111111111111111111110
其实对于 E_NOTICE 使用 & ~ 或者 ^ 的结果, 出现问题的几率是0, 因为 E_NOTICE 的确是包含在 E_ALL 中
那我们换个常量来用看看, E_STRICT 在 PHP 5.0 中被定义, 而它的特殊性, 导致它并没有被定义在 E_ALL 中,
假设某个童鞋写了一个程序, 而我们的程序作者同学对 E_STRICT 不包含在 E_ALL 中并不知情
error_reporting(E_ALL ^ E_STRICT);
这时问题就出现了, 假定当前PHP版本为5.2, 这时
E_STRICT = 2048 = 00000000000000000000100000000000
这里可以看出来, 6143的第12位为0, 而2048为1,
###########################################
我们来说^是什么, ^的作用是: 当 操作数A 和 操作数B 中当前位不同时, 返回结果的当前位设为1, 反过来理解就是, 当 A或B 中当前位相同时, 返回的结果的当前位为0
而我们的作者童鞋正是希望它的反向结果,也就是由于A/B中当前位相同,所以得到0,相当于去掉这个2048,事与愿违的是,,
由于6143中不包含2048, 所以6143和2048的每一位都不同, 所以我们的6143被填上了第12位的1, 变成了8191, 而不是预期的去掉第12位的1, 而作者的意图很明显的是希望去掉它, 很遗憾的是作者并不知道它本来就不在其中
程序运行的结果就是所有的E_STRICT错误被展示给所有访问者欣赏
###########################################
那么我们再看 & ~的结果
首先说, &的含义是 将 A 和 B 中当前位都为1的位设为1, 反过来就是 A 或 B 中任意一个的当前位不为1, 当前位的结果都是 0
而~的含义是将操作数种所有的位翻转过来, 以前是1的变成0, 以前是0的变成1, 所以:
那么接下来由于 6143 的第12位为0, 被翻转的2048中第12位也为0, 而 & 只有在 A 和 B
的当前位皆为1时才将结果范围为1,其他皆为0, 那么第12位仍然保持0, 其他位不同的为0, 此时~2048中除第12位其他皆为1,
在6143中原有的为1的位保持不变,其他不同的变成了0,得到的结果仍然是6143
###########################################
至此我们得到一个结论
使用 A^B 希望将B排除在外, 希望这个条件成立, 只有在A中绝对包含B的情况下才能实现,而A中不包含B的情况下,相当于A加上B, 也就是说 ^ 在A中有B时去掉B,在A中没有B时加上B,是这么个作用
而使用 A&~B可以在无论是否已知A中是否包含B的情况下都可以无条件的让结果中不包含B, 等于说安全的从A中去掉B
###########################################
捎带介绍下 | , 它的作用是 A 和 B 中任意一个当前位为1的情况下, 结果的当前位即为1 , 这相当于 无论中 A中是否存在B, 都可以安全的添加B,不会让结果溢出
###########################################
简易理解方式:
使用 A & B : 返回双方都包含的部分, 可用于判断某个或某些位是否存在
使用 A & ~B : A中有没有B都去掉B,不影响其他位
使用 A | B : A中有没有B都加上B, 不影响其他位