char* 和 std::uint8_t* 之间的reinterpret_cast - 安全吗?

2024-04-04

现在我们有时都必须使用二进制数据。在 C++ 中,我们使用字节序列,并且从一开始char是我们的基石。定义为有sizeof为 1 时,它是字节。所有库 I/O 函数都使用char默认情况下。一切都很好,但总是有一点担心,一点奇怪的事情困扰着一些人——一个字节中的位数是实现定义的。

因此,在 C99 中,决定引入几种 typedef,以便开发人员轻松表达自己的固定宽度整数类型。当然,这是可选的,因为我们不想损害可移植性。他们之中,uint8_t,迁移到 C++11 中为std::uint8_t,一种固定宽度的 8 位无符号整数类型,对于真正想要使用 8 位字节的人来说是完美的选择。

因此,开发人员接受了新工具并开始构建库,明确声明他们接受 8 位字节序列,如std::uint8_t*, std::vector<std::uint8_t>或其他方式。

但是,也许经过深思熟虑,标准化委员会决定不要求实施std::char_traits<std::uint8_t>因此禁止开发人员轻松且可移植地实例化,例如,std::basic_fstream<std::uint8_t>并且轻松阅读std::uint8_ts 作为二进制数据。或者,我们中的一些人可能并不关心一个字节中的位数,而是对此感到满意。

但不幸的是,两个世界发生碰撞,有时你必须将数据视为char*并将其传递给期望的库std::uint8_t*。但等等,你说,不是char可变位和std::uint8_t固定为8?会导致数据丢失吗?

嗯,对此有一个有趣的标准语。这char定义为恰好保存一个字节,并且字节是内存的最低可寻址块,因此不可能存在位宽小于的类型char。接下来,它被定义为能够保存 UTF-8 代码单元。这给了我们最小值 - 8 位。现在我们有一个需要 8 位宽的 typedef 和一个至少 8 位宽的类型。但还有其他选择吗?是的,unsigned char。记住这个符号char是实现定义的。还有其他类型吗?值得庆幸的是,没有。所有其他整数类型的所需范围均超出 8 位。

最后,std::uint8_t是可选的,这意味着如果未定义该类型,则使用该类型的库将不会编译。但如果编译通过呢?我可以非常有信心地说,这意味着我们处于一个具有 8 位字节的平台上,并且CHAR_BIT == 8.

一旦我们知道我们有 8 位字节,std::uint8_t实现为char or unsigned char,我们可以假设我们可以做reinterpret_cast from char* to std::uint8_t*反之亦然?它是便携式的吗?

这就是我的标准语阅读能力失败的地方。我读到有关安全派生指针的内容([basic.stc.dynamic.safety]),据我了解,以下内容:

std::uint8_t* buffer = /* ... */ ;
char* buffer2 = reinterpret_cast<char*>(buffer);
std::uint8_t buffer3 = reinterpret_cast<std::uint8_t*>(buffer2);

如果我们不碰就安全buffer2。如我错了请纠正我。

因此,考虑到以下前提条件:

  • CHAR_BIT == 8
  • std::uint8_t被定义为。

是否便携且安全施放char* and std::uint8_t*来回,假设我们正在处理二进制数据并且可能缺乏符号char没关系吗?

我希望能参考该标准并附上解释。

编辑:谢谢,杰里·科芬。我将添加标准中的引用([basic.lval],§3.10/10):

如果程序尝试通过除其中之一以外的泛左值来访问对象的存储值 以下类型的行为未定义:

...

— char 或 unsigned char 类型。

EDIT2:好的,更深入。std::uint8_t不保证是 typedefunsigned char。它可以实现为扩展无符号整数类型§3.10/10 中不包含扩展无符号整数类型。现在怎么办?


好吧,让我们变得真正迂腐。看完之后this https://stackoverflow.com/questions/98650/what-is-the-strict-aliasing-rule, this http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html and this http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html,我非常有信心我理解这两个标准背后的意图。

所以,做reinterpret_cast from std::uint8_t* to char*然后取消引用结果指针是safe and portable并明确允许[基本.lval] http://eel.is/c++draft/basic.lval#11.3.

然而,做reinterpret_cast from char* to std::uint8_t*然后取消引用结果指针违反了严格的别名规则 and is 未定义的行为 if std::uint8_t被实现为扩展无符号整数类型.

但是,有两种可能的解决方法,首先:

static_assert(std::is_same_v<std::uint8_t, char> ||
    std::is_same_v<std::uint8_t, unsigned char>,
    "This library requires std::uint8_t to be implemented as char or unsigned char.");

有了这个断言,您的代码将不会在平台上编译,否则会导致未定义的行为。

Second:

std::memcpy(uint8buffer, charbuffer, size);

偏好设置 http://en.cppreference.com/w/cpp/string/byte/memcpystd::memcpy以数组形式访问对象unsigned char是这样safe and portable.

重申一下,以便能够reinterpret_cast之间char* and std::uint8_t*并使用结果指针portably and safely为了 100% 符合标准,必须满足以下条件:

  • CHAR_BIT == 8.
  • std::uint8_t被定义为。
  • std::uint8_t被实现为char or unsigned char.

实际上,上述条件在 99% 的平台上都成立,并且可能没有一个平台前 2 个条件为真,而第 3 个条件为假。

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

char* 和 std::uint8_t* 之间的reinterpret_cast - 安全吗? 的相关文章

  • 部署 MVC4 项目时出错:找不到文件或程序集

    过去 我只需使用 Visual Studio 2012 发布到 AWS 菜单项即可部署我的 MVC4 网站 到 AWS Elastic Beanstalk 现在 程序可以在本地编译并运行 但无法部署 从消息来看 它似乎正在寻找不在当前部署的
  • 创建 DirectoryEntry 实例以供测试使用

    我正在尝试创建 DirectoryEntry 的实例 以便可以使用它来测试将传递 DirectoryEntry 的一些代码 然而 尽管进行了很多尝试 我还是找不到实例化 DE 并初始化它的 PropertyCollection 的方法 我有
  • 属性对象什么时候创建?

    由于属性实际上只是附加到程序集的元数据 这是否意味着属性对象仅根据请求创建 例如当您调用 GetCustomAttributes 时 或者它们是在创建对象时创建的 或者 前两个的组合 在由于 CLR 的属性扫描而创建对象时创建 从 CLR
  • Cygwin 下使用 CMake 编译库

    我一直在尝试使用 CMake 来编译 TinyXML 作为一种迷你项目 尝试学习 CMake 作为补充 我试图将其编译成动态库并自行安装 以便它可以工作 到目前为止 我已经设法编译和安装它 但它编译成 dll 和 dll a 让它工作的唯一
  • 如何在 WPF RichTextBox 中跟踪 TextPointer?

    我正在尝试了解 WPF RichTextBox 中的 TextPointer 类 我希望能够跟踪它们 以便我可以将信息与文本中的区域相关联 我目前正在使用一个非常简单的示例来尝试弄清楚发生了什么 在 PreviewKeyDown 事件中 我
  • c 中的错误:声明隐藏了全局范围内的变量

    当我尝试编译以下代码时 我收到此错误消息 错误 声明隐藏了全局范围内的变量 无效迭代器 节点 根 我不明白我到底在哪里隐藏或隐藏了之前声明的全局变量 我怎样才能解决这个问题 typedef node typedef struct node
  • c# Asp.NET MVC 使用FileStreamResult下载excel文件

    我需要构建一个方法 它将接收模型 从中构建excel 构建和接收部分完成没有问题 然后使用内存流导出 让用户下载它 不将其保存在服务器上 我是 ASP NET 和 MVC 的新手 所以我找到了指南并将其构建为教程项目 public File
  • HttpClient 像浏览器一样请求

    当我通过 HttpClient 类调用网站 www livescore com 时 我总是收到错误 500 可能服务器阻止了来自 HttpClient 的请求 1 还有其他方法可以从网页获取html吗 2 如何设置标题来获取html内容 当
  • 基于范围的 for 循环中的未命名循环变量?

    有没有什么方法可以不在基于范围的 for 循环中 使用 循环变量 同时也避免编译器发出有关未使用它的警告 对于上下文 我正在尝试执行以下操作 我启用了 将警告视为错误 并且我不想进行像通过在某处毫无意义地提及变量来强制 使用 变量这样的黑客
  • 使用 LINQ 查找列表中特定类型的第一个元素

    使用 LINQ 和 C 在元素列表中查找特定类型的第一个项目的最短表示法是什么 var first yourCollection OfType
  • Windows 10 中 Qt 桌面应用程序的缩放不当

    我正在为 Windows 10 编写一个简单的 Qt Widgets Gui 应用程序 我使用的是 Qt 5 6 0 beta 版本 我遇到的问题是它根本无法缩放到我的 Surfacebook 的屏幕上 这有点难以判断 因为 SO 缩放了图
  • 像“1$”这样的位置参数如何与 printf() 一起使用?

    By man I find printf d width num and printf 2 1 d width num 是等价的 但在我看来 第二种风格应该与以下相同 printf d num width 然而通过测试似乎man是对的 为什
  • 什么是 C 语言的高效工作流程? - Makefile + bash脚本

    我正在开发我的第一个项目 该项目将跨越多个 C 文件 对于我的前几个练习程序 我只是在中编写了我的代码main c并使用编译gcc main c o main 当我学习时 这对我有用 现在 我正在独自开展一个更大的项目 我想继续自己进行编译
  • 在 URL 中发送之前对特殊字符进行百分比编码

    我需要传递特殊字符 如 等 Facebook Twitter 和此类社交网站的 URL 为此 我将这些字符替换为 URL 转义码 return valToEncode Replace 21 Replace 23 Replace 24 Rep
  • 将日期参数传递给对 MVC 操作的 ajax 调用的安全方法

    我有一个 MVC 操作 它的参数之一是DateTime如果我通过 17 07 2012 它会抛出一个异常 指出参数为空但不能有空值 但如果我通过01 07 2012它被解析为Jan 07 2012 我将日期传递给 ajax 调用DD MM
  • EPPlus Excel 更改单元格颜色

    我正在尝试将给定单元格的颜色设置为另一个单元格的颜色 该单元格已在模板中着色 但worksheet Cells row col Style Fill BackgroundColor似乎没有get财产 是否可以做到这一点 或者我是否必须在互联
  • 如何在内存中存储分子?

    我想将分子存储在内存中 这些可以是简单的分子 Methane CH4 C H bond length 108 7 pm H H angle 109 degrees But also more complex molecules like p
  • 在Linux中使用C/C++获取机器序列号和CPU ID

    在Linux系统中如何获取机器序列号和CPU ID 示例代码受到高度赞赏 Here http lxr linux no linux v2 6 39 arch x86 include asm processor h L173Linux 内核似
  • 方法参数内的变量赋值

    我刚刚发现 通过发现错误 你可以这样做 string s 3 int i int TryParse s hello out i returns false 使用赋值的返回值是否合法 Obviously i is but is this th
  • 不同类型的指针可以互相分配吗?

    考虑到 T1 p1 T2 p2 我们可以将 p1 分配给 p2 或反之亦然吗 如果是这样 是否可以不使用强制转换来完成 或者我们必须使用强制转换 首先 让我们考虑不进行强制转换的分配 C 2018 6 5 16 1 1 列出了简单赋值的约束

随机推荐

  • 传递Physics2DShapeQueryParameters 层进行检查

    我目前正在为我的 2D 自上而下游戏开发一个构建系统 最后一步是检查是否有任何物体 例如树或玩家 阻碍了物品的放置 经过一些研究后 我发现使用Physics2DShapeQueryParameters 是正确的方法 我唯一的问题是我不知道如
  • 仅克隆雪花元数据

    我想克隆 Snowflake 数据库的外壳 仅元数据 无数据 这可能吗 我检查了文档并没有找到解决方案 如果您只是想获取现有数据库的空壳 则可以克隆整个数据库 然后编写脚本截断数据库中存在的所有表 克隆不会添加任何数据 并且克隆上的截断速度
  • ServiceStack.Text序列化循环引用

    我需要像这样序列化对象图 public class A public B Link1 get set public class B public A Link2 get set 这样json只得到两个实例 但又被正确反序列化了 例如 使用元
  • Rails 5.1 升级后控制器测试发出调试(失败)消息

    我最近将一个项目升级到Rails 5 1 所有弃用警告均已修复 所有测试都通过 我使用rspec rails 控制器测试使用 ActiveJob 调用邮件程序现在正在呈现冗长的警告消息 ActiveJob ActionMailer Deli
  • AllegroGraph 检查现有三元组

    我正在使用 AllegroGraph 4 我有一个三元组存储 并且只有在新的三元组尚不存在时我才会尝试添加它们 这是我的 Prolog 查询 select news alfas news a news tst has annotation
  • 参考OpenAPI 3.0中的self

    我在 OpenAPI 3 0 中有一个数据模型定义 使用 SwaggerHub 来显示 UI 我希望模型的属性之一是related 它是同一模型的属性数组 Foo properties title type string related t
  • Keras 误解训练数据形状

    我的训练数据的形式为 15 其中 是一个可变长度 创建模型时我指定了这一点 inp Input shape None 15 conv Conv1D 32 3 padding same activation relu inp 我的训练数据的形
  • PHP 系统() 参数

    我有以下代码执行C 程序 and 输出它 div div 我怎样才能做到这一点您可以将参数传递给 c 程序 这样说 如果这是c program include
  • 无点风格的简单 Haskell 函数

    我试图了解如何将 Haskell 中的函数转换为无点表示法 我看见这个例子 https stackoverflow com questions 2464406 point free in haskell 但它比我正在寻找的更复杂 我觉得我理
  • Spring Boot 应用程序无法加载 SPI 实现

    我有一个Maven模块A中定义的SPI接口 In Module B 这是一个 spring boot 应用程序 我已经定义了META INF services
  • 使用 C# 为字典中的一个键添加多个位图值

    我有一本字典来存储用于 OCR 目的的图案图像 我从字典中抓取了这些位图 并与我从图像中裁剪的位图进行了比较 如果它们匹配 gt 抓取了密钥 OCR 部分已完成 问题就出现在这里 一个Key应该由几个不同的位图 即值 来表示 如何将多个位图
  • vue-loader:如何在 webpack 4 和 vue-cli3 中使用 vue-loader v15

    我使用的是最新版本的 vue cli3webpack4 and vue loader v15 我要配置vue loader 但是有一个错误 Error VueLoaderPlugin Error No matching use for vu
  • 将多行合并为一行

    我想知道将以下行的数据合并到另一个视图中的单行的最佳方法 这些是当前显示的结果 Type ID Client ID PBX Vendor 127 090820006311404926326C Aastra 127 0908200063114
  • Encog/neuroph 保存神经网络

    我是神经网络领域的新手 说实话 我几天前才开始 我想在我的 OCR 应用程序中使用神经网络来识别手写文本 我想知道的是 是否可以在初始训练后训练网络 换句话说 我将在开始时训练几个字符 但我想稍后向网络添加更多字符 而不影响之前训练的数据的
  • System.Text.Json 中的 DefaultContractResolver 等效项

    我正在从 Newtonsoft 转换一些逻辑 并找到以下实现之一 public class CustomDataContractResolver DefaultContractResolver public Dictionary
  • 带有过滤条件的 LINQ 连接

    linq 中是如何完成这样的事情的 它在 JOIN 上有过滤条件 这是摘自这个问题 SQL过滤条件在连接条件或where子句中哪个更有效 https stackoverflow com questions 1401889 sql filte
  • React Redux:如何处理 RTK 查询/突变打字稿中的错误?

    我正在使用带有 RTK 突变的 Typescript 一切正常 但如果我以特定 JSON 格式从后端发送任何错误 例如 status Error message Something went wrong 当我检查浏览器网络选项卡时 它会向我
  • 使文本框不可编辑

    使用 C asp net 与 05 进行比较 我有一个要求 我必须在文本框中填充 gridview 上的一些数据 这些数据来自数据库并使其只读 此后 用户无法在 gridview 模板字段上输入任何文本 如果我设置文本框Enabled fa
  • 在连接的自定义字段上使用过滤表达式时 SSS_INVALID_SRCH_FILTER_JOIN

    SuiteScript v1 搜索项目记录类型 customrecord sp ecom item infoseo 是自定义记录类型 具有一个名为 custrecord sp ecom item seo 的字段 该字段引用项目记录 它还具有
  • char* 和 std::uint8_t* 之间的reinterpret_cast - 安全吗?

    现在我们有时都必须使用二进制数据 在 C 中 我们使用字节序列 并且从一开始char是我们的基石 定义为有sizeof为 1 时 它是字节 所有库 I O 函数都使用char默认情况下 一切都很好 但总是有一点担心 一点奇怪的事情困扰着一些