首页 > 解决方案 > C ++中相互转换不同签名类型的最佳方法?

问题描述

通信对等方发送了一个 uint64_t 数据字段,它带有我需要存储到不支持无符号整数类型的 Postgresql-11 数据库中的订单 ID。虽然实际数据可能超过 2^63,但我认为INT8Postgresql11 中的一个文件可以容纳它,如果我仔细进行一些转换。

假设有:

uint64_t order_id = 123; // received
int64_t  to_db;          // to be writed into db

我计划使用以下方法之一将 uint64_t 值转换为 int64_t 值:

  1. to_db = order_id; // 直接赋值;
  2. to_db = (int64_t)order_id; //c 风格的强制转换;
  3. to_db = static_cast<int64_t>(order_id);
  4. to_db = *reinterpret_cast<const int64_t*>( &order_id );

当我需要从数据库加载它时,我可以进行反向转换。

我知道它们都可以工作,我只是对哪个最符合 C++ 标准感兴趣。

换句话说,哪种方法在任何编译器的任何 64 位平台上始终有效?

谢谢!!!

标签: c++castingreinterpret-caststatic-castsignedness

解决方案


取决于它将在哪里编译和运行......没有 C++20 支持的任何不能完全移植的。

没有那个的最安全的方法是通过改变值的范围来自己进行转换,比如

int64_t to_db = (order_id > (uint64_t)LLONG_MAX) 
           ? int64_t(order_id - (uint64_t)LLONG_MAX - 1) 
           : int64_t(order_id ) - LLONG_MIN;

uint64_t from_db = (to_db < 0) 
                    ? to_db + LLONG_MIN
                    : uint64_t(to_db) +  (uint64_t)LLONG_MAX  + 1;

如果order_id大于 (2^63 -1),则order_id - (uint64_t)LLONG_MAX - 1产生非负值。如果不是,则强制转换为有符号是明确定义的,并且减法可确保将值转移到负范围内。

在反向转换期间,to_db + LLONG_MIN将值放入 [0, ULLONG_MAX] 范围内。

并在阅读时做相反的事情。您使用的数据库平台或编译器在将无符号值的二进制表示转换为有符号时可能会做一些糟糕的事情,更不用说确实存在不同的有符号格式。

出于同样的原因,跨平台协议通常涉及使用字符串格式或“最小位值”来将浮点值表示为整数,即编码定点。


推荐阅读