在布尔值中设置额外的位可以使其同时为 true 和 false

2024-01-01

如果我得到一个bool变量并将其第二位设置为 1,则变量同时计算为 true 和 false。用gcc6.3编译以下代码-g选项, (gcc-v6.3.0/Linux/RHEL6.0-2016-x86_64/bin/g++ -g main.cpp -o mytest_d)并运行可执行文件。你会得到以下结果。

T怎么能同时等于true和false呢?

       value   bits 
       -----   ---- 
    T:   1     0001
after bit change
    T:   3     0011
T is true
T is false

当您使用不同语言(例如 Fortran)调用函数时,可能会发生这种情况,其中 true 和 false 定义与 C++ 不同。对于 Fortran,如果任何位不为 0,则该值为 true,如果所有位都为零,则该值为 false。

#include <iostream>
#include <bitset>

using namespace std;

void set_bits_to_1(void* val){
  char *x = static_cast<char *>(val);

  for (int i = 0; i<2; i++ ){
    *x |= (1UL << i);
  }
}

int main(int argc,char *argv[])
{

  bool T = 3;

  cout <<"       value   bits " <<endl;
  cout <<"       -----   ---- " <<endl;
  cout <<"    T:   "<< T <<"     "<< bitset<4>(T)<<endl;

  set_bits_to_1(&T);


  bitset<4> bit_T = bitset<4>(T);
  cout <<"after bit change"<<endl;
  cout <<"    T:   "<< T <<"     "<< bit_T<<endl;

  if (T ){
    cout <<"T is true" <<endl;
  }

  if ( T == false){
    cout <<"T is false" <<endl;
  }


}

////////////////////////////////////////////////////////////////////// // 使用 ifort 编译时与 C++ 不兼容的 Fortran 函数。

       logical*1 function return_true()
         implicit none

         return_true = 1;

       end function return_true

在 C++ 中,a 的位表示(甚至大小)bool是否已定义实现;通常它被实现为char-sized 类型,取 1 或 0 作为可能值。

如果您将其值设置为与允许的值不同的任何值(在这种特定情况下,通过别名bool通过一个char并修改其位表示),你就违反了语言的规则,所以任何事情都有可能发生。特别是,标准中明确规定“损坏”bool可能表现为两者true and false(或两者都不true nor false) 同时:

Using a bool以本国际标准描述为“未定义”的方式获取值,例如通过检查未初始化的自动对象的值,可能会导致其表现得好像两者都不是true nor false

(C++11,[basic.fundamental],注释 47)


在这种特殊情况下,你可以看到它是如何导致这种奇怪的情况的 https://gcc.godbolt.org/z/3P5DYR: 首先if被编译为

    movzx   eax, BYTE PTR [rbp-33]
    test    al, al
    je      .L22

哪个加载T in eax(扩展为零),如果全为零则跳过打印;下一个 if 是

    movzx   eax, BYTE PTR [rbp-33]
    xor     eax, 1
    test    al, al
    je      .L23

考试if(T == false)变换为if(T^1),仅翻转低位。这对于有效的bool,但对于你的“破损”的来说,它并没有减少它。

请注意,这个奇怪的序列仅在低优化级别下生成;在更高的级别,这通常会归结为零/非零检查,并且像您这样的序列可能会变成单个测试/条件分支 https://gcc.godbolt.org/z/9I0OR-。无论如何,在其他情况下你都会遇到奇怪的行为,例如求和时bool值转换为其他整数:

int foo(bool b, int i) {
    return i + b;
}

becomes https://gcc.godbolt.org/z/07suQv

foo(bool, int):
        movzx   edi, dil
        lea     eax, [rdi+rsi]
        ret

where dil“可信”为 0/1。


如果你的程序全部是 C++,那么解决方案很简单:不要中断bool以这种方式值,避免弄乱它们的位表示,一切都会顺利进行;特别是,即使您将整数分配给bool编译器将发出必要的代码以确保结果值是有效的bool,所以你的bool T = 3确实安全,并且T最终会得到一个true在它的胆量里。

相反,如果您需要与用其他语言编写的代码进行互操作,而这些语言可能不具有相同的理念bool是,只是避免bool对于“边界”代码,并将其编组为适当大小的整数。它适用于条件语句 & co。一样好。


有关 Fortran/互操作性方面问题的更新

免责声明我对 Fortran 的了解只是我今天早上在标准文档中读到的,而且我有一些带有 Fortran 列表的打孔卡,我将它们用作书签,所以对我要宽容一点。

首先,这种语言互操作性的东西不是语言标准的一部分,而是平台 ABI 的一部分。当我们谈论 Linux x86-64 时,相关文档是System V x86-64 ABI https://www.uclibc.org/docs/psABI-x86_64.pdf.

首先,没有任何地方指定 C_Bool类型(定义与 C++ 相同)bool3.1.2 注释 †) 与 Fortran 具有任何类型的兼容性LOGICAL;特别是,在 9.2.2 中,表 9.2 规定“普通”LOGICAL被映射到signed int. About TYPE*N类型它说

The “TYPE*N” 符号指定类型的变量或聚合成员TYPE应占据N字节存储。

(ibid.)

没有明确指定等效类型LOGICAL*1,这是可以理解的:它甚至不是标准的;事实上,如果你尝试编译一个包含以下内容的 Fortran 程序LOGICAL*1在 Fortran 95 兼容模式下,您会收到有关 ifort 的警告

./example.f90(2): warning #6916: Fortran 95 does not allow this length specification.   [1]

    logical*1, intent(in) :: x

------------^

并通过努力

./example.f90:2:13:
     logical*1, intent(in) :: x
             1
Error: GNU Extension: Nonstandard type declaration LOGICAL*1 at (1)

所以水已经浑了;所以,结合上面的两个规则,我会选择signed char为了安全起见。

However:ABI 还指定:

类型的值LOGICAL are .TRUE.实施为 1 和.FALSE.实现为 0。

所以,如果你有一个程序在 a 中存储除 1 和 0 之外的任何内容LOGICAL value, 你已经超出了 Fortran 方面的规范!你说:

一个fortranlogical*1具有相同的表示bool,但在 Fortran 中,如果位为 00000011,则为true,在 C++ 中它是未定义的。

最后这句话是不正确的,Fortran 标准与表示无关,而 ABI 明确表示相反。事实上,您可以通过以下方式轻松地看到这一点:检查 gfort 的输出LOGICAL比较 https://gcc.godbolt.org/z/dh-a-c:

integer function logical_compare(x, y)
    logical, intent(in) :: x
    logical, intent(in) :: y
    if (x .eqv. y) then
        logical_compare = 12
    else
        logical_compare = 24
    end if
end function logical_compare

becomes

logical_compare_:
        mov     eax, DWORD PTR [rsi]
        mov     edx, 24
        cmp     DWORD PTR [rdi], eax
        mov     eax, 12
        cmovne  eax, edx
        ret

你会注意到有一条直线cmp介于两个值之间,无需先对它们进行标准化(与ifort,在这方面比较保守)。

更有趣的是:无论 ABI 怎么说,ifort 默认情况下使用非标准表示LOGICAL;这在-fpscomp logicals https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-fpscompswitch 文档,其中还指定了一些有趣的细节LOGICAL和跨语言兼容性:

指定具有非零值的整数被视为 true,具有零值的整数被视为 false。文字常量 .TRUE。具有整数值 1 和文字常量 .FALSE。整数值为 0。此表示法由版本 8.0 之前的 Intel Fortran 版本和 Fortran PowerStation 使用。

默认为fpscomp nologicals,它指定奇数整数值(低位 1)被视为 true,偶数整数值(低位 0)被视为 false。

文字常量 .TRUE。整数值为 -1,文字常量为 .FALSE。具有整数值 0。此表示法由 Compaq Visual Fortran 使用。 Fortran 标准未指定 LOGICAL 值的内部表示。在逻辑上下文中使用整数值的程序,或者将逻辑值传递给用其他语言编写的过程的程序是不可移植的,并且可能无法正确执行。英特尔建议您避免依赖逻辑值内部表示的编码实践。

(强调已添加)

现在,一个的内部表示LOGICAL通常应该不成问题,因为据我所知,如果你“遵守规则”并且不跨越语言界限,你就不会注意到。对于符合标准的程序,之间没有“直接转换”INTEGER and LOGICAL;我认为你唯一能推开的方式INTEGER into a LOGICAL似乎是TRANSFER,本质上是不可移植的并且不提供真正的保证,或者非标准INTEGERLOGICAL赋值时的转换。

后一种已记录 https://gcc.gnu.org/onlinedocs/gfortran/Implicitly-convert-LOGICAL-and-INTEGER-values.html通过 gfort 始终导致非零 ->.TRUE., 零 ->.FALSE., and 你可以看到 https://gcc.godbolt.org/z/y5taV2在所有情况下,都会生成代码来实现这一点(即使在使用旧表示形式的 ifort 中,它是复杂的代码),因此您似乎无法将任意整数推入LOGICAL这样。

logical*1 function integer_to_logical(x)
    integer, intent(in) :: x
    integer_to_logical = x
    return
end function integer_to_logical
integer_to_logical_:
        mov     eax, DWORD PTR [rdi]
        test    eax, eax
        setne   al
        ret

的逆向转换为LOGICAL*1是一个直整数零扩展(gfort),因此,为了遵守上面链接的文档中的合同,它显然期望LOGICAL值为 0 或 1。

但一般来说,这些转换的情况是a bit https://www.reddit.com/r/fortran/comments/a8dzvs/ifort_implicit_logicaltointeger_conversion_of/ of a mess https://groups.google.com/forum/#!topic/gg95/yQqAlfzIBDU,所以我就远离他们。


所以,长话短说:避免投入INTEGER数据进入LOGICAL值,因为即使在 Fortran 中它也很糟糕,并确保使用正确的编译器标志来获取符合 ABI 的布尔值表示,并且与 C/C++ 的互操作性应该很好。但为了更加安全,我只是使用普通char在C++方面。

最后,根据我收集到的信息从文档中 https://software.intel.com/en-us/fortran-compiler-developer-guide-and-reference-scalar-types,在 ifort 中,有一些与 C 的互操作性的内置支持,包括布尔值;你可以尝试利用它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在布尔值中设置额外的位可以使其同时为 true 和 false 的相关文章

  • 具有子列表属性映射问题的自动映射器

    我有以下型号 Models public class Dish Required public Int64 ID get set Required public string Name get set Required public str
  • 为什么大多数 C 开发人员使用 Define 而不是 const? [复制]

    这个问题在这里已经有答案了 在许多程序中 define与常量具有相同的用途 例如 define FIELD WIDTH 10 const int fieldWidth 10 我通常认为第一种形式优于另一种形式 它依赖于预处理器来处理基本上是
  • 向 ExpandoObject 添加方法时,“关键字 'this' 在静态属性、静态方法或静态字段初始值设定项中无效”

    我尝试向 ExpandoObject 添加一个动态方法 该方法将返回属性 动态添加 给它 但它总是给我错误 我在这里做错了什么吗 using System using System Collections Generic using Sys
  • 为什么要序列化对象需要 Serialized 属性

    根据我的理解 SerializedAttribute 不提供编译时检查 因为它都是在运行时完成的 如果是这样 那么为什么需要将类标记为可序列化呢 难道序列化器不能尝试序列化一个对象然后失败吗 这不就是它现在所做的吗 当某些东西被标记时 它会
  • C++:重写已弃用的虚拟方法时出现弃用警告

    我有一个纯虚拟类 它有一个纯虚拟方法 应该是const 但不幸的是不是 该接口位于库中 并且该类由单独项目中的其他几个类继承 我正在尝试使用这个方法const不会破坏兼容性 至少在一段时间内 但我找不到在非常量方法重载时产生警告的方法 以下
  • POCO HTTPSClientSession 发送请求时遇到问题 - 证书验证失败

    我正在尝试使用 POCO 库编写一个向服务器发出 HTTPS 请求的程序 出于测试目的 我正在连接到具有自签名证书的服务器 并且我希望允许客户端进行连接 为了允许这种情况发生 我尝试安装InvalidCertificateHandler这是
  • 如何配置 WebService 返回 ArrayList 而不是 Array?

    我有一个在 jax ws 上实现的 java Web 服务 此 Web 服务返回用户的通用列表 它运行得很好 Stateless name AdminToolSessionEJB RemoteBinding jndiBinding Admi
  • 访问者和模板化虚拟方法

    在一个典型的实现中Visitor模式 该类必须考虑基类的所有变体 后代 在许多情况下 访问者中的相同方法内容应用于不同的方法 在这种情况下 模板化的虚拟方法是理想的选择 但目前这是不允许的 那么 模板化方法可以用来解析父类的虚方法吗 鉴于
  • 如何从 C# 控制器重定向到外部 url

    我使用 C 控制器作为网络服务 在其中我想将用户重定向到外部网址 我该怎么做 Tried System Web HttpContext Current Response Redirect 但没有成功 使用控制器的重定向 http msdn
  • 如何重置捕获像素的值

    我正在尝试创建一个 C 函数 该函数返回屏幕截图位图中每四个像素的 R G 和 B 值 这是我的代码的一部分 for int ix 4 ix lt 1366 ix ix 4 x x 4 for int iy 3 iy lt 768 iy i
  • 生产代码中的 LRU 实现

    我有一些 C 代码 需要使用 LRU 技术实现缓存替换 目前我知道两种实现LRU缓存替换的方法 每次访问缓存数据时使用时间戳 最后比较替换时的时间戳 使用缓存项的堆栈 如果最近访问过它们 则将它们移动到顶部 因此最后底部将包含 LRU 候选
  • 通过 NHibernate 进行查询,无需 N+1 - 包含示例

    我有一个 N 1 问题 我不知道如何解决它 可以在这个问题的底部找到完全可重复的样本 因此 如果您愿意 请创建数据库 设置 NUnit 测试和所有附带的类 并尝试在本地消除 N 1 这是我遇到的真实问题的匿名版本 众所周知 这段代码对于帮助
  • 在 C 中使用 GNU automake 中的解析器

    我是 GNU autotools 的新手 在我的项目中使用了 lex 和 yacc 解析器 将它们作为 makefile am 中的源代码会产生以下错误 配置 in AC CHECK PROGS YACC bison yacc none i
  • 迭代 my_dict.keys() 并修改字典中的值是否会使迭代器失效?

    我的例子是这样的 for my key in my dict keys my dict my key mutate 上述代码的行为是否已定义 假设my dict是一本字典并且mutate是一个改变其对象的方法 我担心的是 改变字典中的值可能
  • 如何一步步遍历目录树?

    我发现了很多关于遍历目录树的示例 但我需要一些不同的东西 我需要一个带有某种方法的类 每次调用都会从目录返回一个文件 并逐渐遍历目录树 请问我该怎么做 我正在使用函数 FindFirstFile FindNextFile 和 FindClo
  • 耐用功能是否适合大量活动?

    我有一个场景 需要计算 500k 活动 都是小算盘 由于限制 我只能同时计算 30 个 想象一下下面的简单示例 FunctionName Crawl public static async Task
  • 使用 C# 从 DateTime 获取日期

    愚蠢的问题 给定日期时间中的日期 我知道它是星期二 例如我如何知道它的 tue 2 和 mon 1 等 Thanks 您正在寻找星期几 http msdn microsoft com en us library system datetim
  • 用于 C# XNA 的 Javascript(或类似)游戏脚本

    最近我准备用 XNA C 开发另一个游戏 上次我在 XNA C 中开发游戏时 遇到了必须向游戏中添加地图和可自定义数据的问题 每次我想添加新内容或更改游戏角色的某些值或其他内容时 我都必须重建整个游戏或其他内容 这可能需要相当长的时间 有没
  • 带重定向标准流的 C# + telnet 进程立即退出

    我正在尝试用 C 做一个 脚本化 telnet 项目 有点类似于Tcl期望 http expect nist gov 我需要为其启动 telnet 进程并重定向 和处理 其 stdin stdout 流 问题是 生成的 telnet 进程在
  • Googletest:如何异步运行测试?

    考虑到一个包含数千个测试的大型项目 其中一些测试需要几分钟才能完成 如果按顺序执行 整套测试需要一个多小时才能完成 通过并行执行测试可以减少测试时间 据我所知 没有办法直接从 googletest mock 做到这一点 就像 async选项

随机推荐

  • Shiny R 反应值内存泄漏

    我试图理解为什么骑自行车时使用闪亮的reactivevalues导致它使用更多内存 上下文是一个用户界面 可以选择自动执行给定的策略 下面的例子基于圣彼得堡悖论 我意识到将整个自动化过程放在单独的函数文件中可能是更好的做法 但我想了解为什么
  • 使用 ExtJS 实现富互联网应用:我应该选择哪个方向?

    我需要一些帮助来选择正确的 RIA 方式 我确实想使用 javascript 小部件库 可能是 ExtJS 但我不确定我是否应该尝试通过 Javascript 进行编程ExtGWT http extjs com products gxt 或
  • PHP 简单 HTML DOM 解析器消亡

    我使用简单的 HTML DOM 解析器来屏幕抓取带有一堆子页面的页面 由于某种原因 它可以很好地解析前 40 个子页面 但当涉及到第 41 个子页面时 它会毫无错误地终止 我已经做了这个测试页 http snuzzer dk pub shd
  • 如何将引发异常的函数转换为返回 Either 的函数?

    假设我有一些引发异常的函数 我正在包装它们以返回Either Throwable
  • 是否有用于利用对称性的对称矩阵乘法的 BLAS 或 LAPACK 子例程?

    我希望有人能帮助我 我正在寻找专门用于两个大且相同的对称矩阵的矩阵乘法的 BLAS 或 LAPACK 子例程 到目前为止 我已经测试了 Dyrk 和 dgemm 例程 两者都非常慢 我想知道是否有特定于对称矩阵平方的例程 任何帮助将不胜感激
  • Microsoft PDC (2009) 中的哪些新闻/谈话将对您作为程序员产生最大影响?

    我已将其设为社区维基 作为一名主要使用 NET的程序员 微软开发平台的功能方向对我的功能工作有很大的影响 最近的 PDC 让我们深入了解了 Microsoft 的开发平台的发展方向 那么您认为 PDC 的哪些内容会对you作为一名程序员 您
  • DataFrame 单元格换行符

    问题很简单 如何防止打印数据框单元格中的换行Jupyter笔记本 不在终端中 我在这里没有看到任何答案 比如使用的答案pd get option display width pd get option display max colwidt
  • gwtbootstrap 始终适用于所有元素

    我想用GWT 引导程序 http gwtbootstrap github io 对于我的应用程序 所以我将 jar 添加到类路径中并在 app gwt xml 中继承它 并且到目前为止它正在工作 我是 Bootstrap 的新手 到目前为止
  • pgAdmin3 连接问题

    我最近正在使用 VMware Workstation 8 设置并运行 Windows 2008 r2 服务器 我正在运行带有 Postgresql 9 1 的 Centos 6 2 虚拟 Linux 盒子 本地一切似乎都正常 我可以通过桥接
  • 无法在 Visual Studio 上加载 ClassDiagram.cd。 “不支持 URI 格式”

    当我尝试打开我的类图时asp net 网络表单项目我收到以下错误 类图 cd 文件已生成 但我无法打开它们 I do have some classes that use the URI class but i don t really t
  • 将 freq 字符串转换为 pandas 中的 DateOffset

    在 pandas 文档中 当谈到诸如 W 或 W SUN 之类的频率字符串时 可以阅读 在幕后 这些频率字符串正在被转换为 pandas DateOffset 的实例 那么 如何在给定字符串的情况下获取 DateOffset 的实例 最终想
  • 如何使用自定义ip地址浏览网页c#/.net

    我正在尝试使用自定义 用户提供的 IP 地址浏览网页 但它不起作用 webBrowser1 成功加载网页 但它没有使用自定义 IP 地址 而是使用真实 IP 地址加载页面 请告诉我如何成功地完成这项工作 这是我的代码 private voi
  • 如何将图像放置在链接内?

    我正在尝试一些非常简单的东西 在链接内我希望有文本和图像 link to NVidia Graphics inventory url class lato do image tag list highlighter png 我希望输出是这样
  • 在循环中使用 SQLAlchemy Session 对象提交数据时出现问题

    我在使用 SQLalchemy 时遇到数据库提交问题 这是我的场景 我有一个要添加到表中的记录列表 将记录添加到表中后 我需要获取插入的记录 Id 并再次插入到第二个表中 我正在单个会话下执行这些操作 下面给出了代码结构 因为我不允许给出代
  • Angular 服务调用另一个服务

    我正在制作一个简单的 Angular 应用程序来管理收入 收入来自我存储在 json 中的项目 用于测试目的 所以 基本上 我使用 Angular 中的一个服务来获取这个 json 并且我希望有另一个服务来调用项目服务并过滤每个项目的收入
  • 未找到符号:引用自:预期位于:平面命名空间 | macOS 大苏尔

    我一直在尝试使用以下方式导入模块 import pyexiv2 这会产生一个错误 Aruns MacBook Air scripts arun python3 99 new camera py crop field Traceback mo
  • uWSGI + virtualenv“没有名为站点的模块”

    所以这似乎是这个设置的一个非常常见的问题 但我找不到任何适用于SO的解决方案 我已经设置了一个非常新的 Ubuntu 15 04 服务器 然后安装了 nginx virtualenv 和 wrapper 和 uWSGI 通过 apt get
  • Roslyn 获取类的依赖项

    我试图确定一个类 它引用什么 其他命名空间或外部库命名空间 对于给定的文档 语法树等来说 似乎是开箱即用的 没有办法做到这一点 而且我需要使用符号查找器 迭代整个代码库中的每个文件 然后调用 find 粘贴找到的引用在地图中 然后向后导航地
  • Objective C - 在哪里释放全局静态变量?

    或者 void initialize 的反义词是什么 这是我的情况 我有一个 Unit 类 其 id initWithName 函数从全局 NSDictionary 获取数据 该全局 NSDictionary 是延迟创建的 在 Unit m
  • 在布尔值中设置额外的位可以使其同时为 true 和 false

    如果我得到一个bool变量并将其第二位设置为 1 则变量同时计算为 true 和 false 用gcc6 3编译以下代码 g选项 gcc v6 3 0 Linux RHEL6 0 2016 x86 64 bin g g main cpp o