在布尔值中设置额外的位可以使其同时为 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 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 结构化绑定中缺少类型信息

    我刚刚了解了 C 中的结构化绑定 但有一件事我不喜欢 auto x y some func is that auto正在隐藏类型x and y 我得抬头看看some func的声明来了解类型x and y 或者 我可以写 T1 x T2 y
  • 如何在 C# 中打开 Internet Explorer 属性窗口

    我正在开发一个 Windows 应用程序 我必须向用户提供一种通过打开 IE 设置窗口来更改代理设置的方法 Google Chrome 使用相同的方法 当您尝试更改 Chrome 中的代理设置时 它将打开 Internet Explorer
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 如何从本机 C(++) DLL 调用 .NET (C#) 代码?

    我有一个 C app exe 和一个 C my dll my dll NET 项目链接到本机 C DLL mynat dll 外部 C DLL 接口 并且从 C 调用 C DLL 可以正常工作 通过使用 DllImport mynat dl
  • WPF 数据绑定到复合类模式?

    我是第一次尝试 WPF 并且正在努力解决如何将控件绑定到使用其他对象的组合构建的类 例如 如果我有一个由两个单独的类组成的类 Comp 为了清楚起见 请注意省略的各种元素 class One int first int second cla
  • 方程“a + bx = c + dy”的积分解

    在等式中a bx c dy 所有变量都是整数 a b c and d是已知的 我如何找到整体解决方案x and y 如果我的想法是正确的 将会有无限多个解 由最小公倍数分隔b and d 但我只需要一个解决方案 我可以计算其余的 这是一个例
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 为什么 C# 2.0 之后没有 ISO 或 ECMA 标准化?

    我已经开始学习 C 并正在寻找标准规范 但发现大于 2 0 的 C 版本并未由 ISO 或 ECMA 标准化 或者是我从 Wikipedia 收集到的 这有什么原因吗 因为编写 审查 验证 发布 处理反馈 修订 重新发布等复杂的规范文档需要
  • 复制目录下所有文件

    如何将一个目录中的所有内容复制到另一个目录而不循环遍历每个文件 你不能 两者都不Directory http msdn microsoft com en us library system io directory aspx nor Dir
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • C++ 继承的内存布局

    如果我有两个类 一个类继承另一个类 并且子类仅包含函数 那么这两个类的内存布局是否相同 e g class Base int a b c class Derived public Base only functions 我读过编译器无法对数
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • 当文件流没有新数据时如何防止fgets阻塞

    我有一个popen 执行的函数tail f sometextfile 只要文件流中有数据显然我就可以通过fgets 现在 如果没有新数据来自尾部 fgets 挂起 我试过ferror and feof 无济于事 我怎样才能确定fgets 当
  • DotNetZip:如何提取文件,但忽略zip文件中的路径?

    尝试将文件提取到给定文件夹 忽略 zip 文件中的路径 但似乎没有办法 考虑到其中实现的所有其他好东西 这似乎是一个相当基本的要求 我缺少什么 代码是 using Ionic Zip ZipFile zf Ionic Zip ZipFile
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • MySQL Connector C/C API - 使用特殊字符进行查询

    我是一个 C 程序 我有一个接受域名参数的函数 void db domains query char name 使用 mysql query 我测试数据库中是否存在域名 如果不是这种情况 我插入新域名 char query 400 spri
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • 现代编译器是否优化乘以 1 和 -1

    如果我写 template
  • 使用 WGL 创建现代 OpenGL 上下文?

    我正在尝试使用 Windows 函数创建 OpenGL 上下文 现代版本 基本上代码就是 创建窗口类 注册班级 创建一个窗口 choose PIXELFORMATDESCRIPTOR并设置它 创建旧版 OpenGL 上下文 使上下文成为当前

随机推荐

  • 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