英文:
Joining two integers into one bigger integer in C++
问题
我需要有两个独立的16位整数,它们可以一起组成一个32位整数。但无论我更改它们中的任何一个,我都需要它们被更新。假设我更改了32位整数的值,我需要它自动覆盖两个16位整数,反之亦然。这是可能的吗?
英文:
I need to have two separate 16-bit integers, that can form a 32-bit integer together. But I need them to be updated whenever I change any of them. Let's say I change the value of the 32-bit, I need it to be automatically written over the two 16-bit ones and vice versa. Is this possible?
答案1
得分: 8
你可以使用代理类来表示你的32位整数:
class Proxy {
private:
uint16_t &_high, &_low;
public:
Proxy(uint16_t &high, uint16_t &low) : _high(high), _low(low) {}
Proxy &operator=(uint32_t whole) {
_high = whole >> 16;
_low = whole & 0xffff;
return *this;
}
operator uint32_t() const {
return (_high << 16) | _low;
}
};
int main() {
uint16_t high = 0xa, low = 0xb;
Proxy whole(high, low);
std::cout << std::hex;
std::cout << whole << '\n'; // a000b
high = 0xc;
low = 0xd;
std::cout << whole << '\n'; // c000d
whole = 0xe000f;
std::cout << high << ' ' << low << '\n'; // e f
return 0;
}
通过提供operator uint32_t
,Proxy
在大多数情况下可以隐式转换为uint32_t
。
英文:
You can use a proxy class to represent your 32-bit integer:
class Proxy {
private:
uint16_t &_high, &_low;
public:
Proxy(uint16_t &high, uint16_t &low) : _high(high), _low(low) {}
Proxy &operator=(uint32_t whole) {
_high = whole >> 16;
_low = whole & 0xffff;
return *this;
}
operator uint32_t() const {
return (_high << 16) | _low;
}
};
int main() {
uint16_t high = 0xa, low = 0xb;
Proxy whole(high, low);
std::cout << std::hex;
std::cout << whole << '\n'; // a000b
high = 0xc;
low = 0xd;
std::cout << whole << '\n'; // c000d
whole = 0xe000f;
std::cout << high << ' ' << low << '\n'; // e f
return 0;
}
By providing operator uint32_t
, Proxy
can be implicitly converted to uint32_t
in most cases.
答案2
得分: 1
这在C++20中变得非常容易,它具有bit_cast
功能,甚至可以在constexpr
函数中使用。以下是三种不同方式的示例代码:
#include <iostream>
#include <array>
#include <cstdint>
#include <bit>
using std::uint32_t, std::uint16_t;
// 独立的函数
void place_low16(std::array<uint16_t, 2>& arr, uint16_t x) { arr[0] = x; }
void place_high16(std::array<uint16_t, 2>& arr, uint16_t x) { arr[1] = x; }
void place_32int(std::array<uint16_t, 2>& arr, uint32_t i) { arr = std::bit_cast<std::array<uint16_t, 2>>(i); }
uint32_t get_ui32(const std::array<uint16_t, 2>& arr) { return std::bit_cast<uint32_t>(arr); }
// 封装
struct PackedInt16 {
std::array<uint16_t, 2> two_uint32s;
void place_low16(uint16_t x) { two_uint32s[0] = x; }
void place_high16(uint16_t x) { two_uint32s[1] = x; }
void place_32int(uint32_t i) { two_uint32s = std::bit_cast<std::array<uint16_t, 2>>(i); }
uint32_t get_ui32() { return std::bit_cast<uint32_t>(two_uint32s); }
};
int main() {
// 独立的函数
std::array<uint16_t, 2> packed_ints;
place_low16(packed_ints, static_cast<uint16_t>(0xffff'ffff)); // 存储在低16位
place_high16(packed_ints, static_cast<uint16_t>(0x1)); // 存储在高16位
uint32_t x = get_ui32(packed_ints); // 获取32位整数
place_32int(packed_ints, x); // 将32位整数存储在打包的int16中
std::cout << x << " " << packed_ints[0] << " " << packed_ints[1] << '\n';
// 输出: 131071 65535 1
// 封装
PackedInt16 packed_ints2;
packed_ints2.place_low16(static_cast<uint16_t>(0xffff'ffff));
packed_ints2.place_high16(static_cast<uint16_t>(0x1));
uint32_t x2 = packed_ints2.get_ui32();
packed_ints2.place_32int(x2);
std::cout << x2 << " " << packed_ints2.two_uint32s[0] << " " << packed_ints2.two_uint32s[1] << '\n';
// 输出: 131071 65535 1
// 直接方法:无函数,无类
std::array<uint16_t, 2> packed_ints3;
packed_ints3[0] = static_cast<uint16_t>(0xffff'ffff);
packed_ints3[1] = 1;
uint32_t x3 = std::bit_cast<uint32_t>(packed_ints3);
packed_ints3 = std::bit_cast<std::array<uint16_t, 2>>(x3);
std::cout << x3 << " " << packed_ints3[0] << " " << packed_ints3[1] << '\n';
// 输出: 131071 65535 1
}
英文:
This gets really easy with c++20 which has bit_cast. It can even be used in constexpr functions. Here are freestanding encapsulated, and really simple direct (no extra functions or classes) versions:
#include <iostream>
#include <array>
#include <cstdint>
#include <bit>
using std::uint32_t, std::uint16_t;
// Free standing functions
void place_low16(std::array<uint16_t, 2>& arr, uint16_t x) {arr[0] = x;}
void place_high16(std::array<uint16_t, 2>& arr, uint16_t x) {arr[1] = x;}
void place_32int(std::array<uint16_t, 2>& arr, uint32_t i){arr = std::bit_cast<std::array<uint16_t, 2>>(i);}
uint32_t get_ui32(const std::array<uint16_t, 2>& arr) {return std::bit_cast<uint32_t>(arr);}
// encapsulated
struct PackedInt16 {
std::array<uint16_t, 2> two_uint32s;
void place_low16(uint16_t x) {two_uint32s[0] = x;}
void place_high16(uint16_t x) { two_uint32s[1] = x; }
void place_32int(uint32_t i) { two_uint32s = std::bit_cast<std::array<uint16_t, 2>>(i); }
uint32_t get_ui32() { return std::bit_cast<uint32_t>(two_uint32s); }
};
int main()
{
// free standing functions
std::array<uint16_t, 2> packed_ints;
place_low16(packed_ints, static_cast<uint16_t>(0xffff'ffff)); //store in low int16
place_high16(packed_ints, static_cast<uint16_t>(0x1)); // store in high int16
uint32_t x = get_ui32(packed_ints); // get 32 bit uint
place_32int(packed_ints, x); // store 32 bit uint in packed int16s
std::cout << x << " " << packed_ints[0] << " " << packed_ints[1] << '\n';
// ouput: 131071 65535 1
// encapsulated
PackedInt16 packed_ints2;
packed_ints2.place_low16(static_cast<uint16_t>(0xffff'ffff));
packed_ints2.place_high16(static_cast<uint16_t>(0x1));
uint32_t x2 = packed_ints2.get_ui32();
packed_ints2.place_32int(x2);
std::cout << x2 << " " << packed_ints2.two_uint32s[0] << " " << packed_ints2.two_uint32s[1] << '\n';
// ouput: 131071 65535 1
// and now the direct approach: No functions, no classes
std::array<uint16_t, 2> packed_ints3;
packed_ints3[0] = static_cast<uint16_t>(0xffff'ffff);
packed_ints3[1] = 1;
uint32_t x3 = std::bit_cast<uint32_t>(packed_ints3);
packed_ints3 = std::bit_cast<std::array<uint16_t, 2>>(x3);
std::cout << x3 << " " << packed_ints3[0] << " " << packed_ints3[1] << '\n';
// ouput: 131071 65535 1
}
答案3
得分: 0
以下是翻译好的内容:
class Uint32BitView16
{
uint32_t& m_data;
unsigned m_shift;
public:
constexpr Uint32BitView16(uint32_t& data, unsigned shift)
: m_data(data),
m_shift(shift)
{
}
constexpr operator uint16_t() const
{
return (m_data >> m_shift);
}
constexpr Uint32BitView16& operator=(uint16_t value)
{
m_data = (m_data & ~static_cast<uint32_t>(0xffff << m_shift)) | (value << m_shift);
return *this;
}
};
int main() {
uint32_t data = 0x01020304;
Uint32BitView16 v1(data, 0);
Uint32BitView16 v2(data, 16);
std::cout << std::hex;
std::cout << static_cast<uint16_t>(v1) << '\n'; // 304
std::cout << static_cast<uint16_t>(v2) << '\n'; // 102
data = 0xffff0000;
std::cout << static_cast<uint16_t>(v1) << '\n'; // 0
std::cout << static_cast<uint16_t>(v2) << '\n'; // ffff
v1 = 0xff;
std::cout << data << '\n'; // ffff00ff
}
希望这对你有帮助。
英文:
You could define a class that behaves similar to a uint16_t
which works with a uint32_t
value stored as reference.
In some cases there's a difference though, e.g. a conversion to uint16_t
won't happen automatically in some cases.
class Uint32BitView16
{
uint32_t& m_data;
unsigned m_shift;
public:
constexpr Uint32BitView16(uint32_t& data, unsigned shift)
: m_data(data),
m_shift(shift)
{
}
constexpr operator uint16_t() const
{
return (m_data >> m_shift);
}
constexpr Uint32BitView16& operator=(uint16_t value)
{
m_data = (m_data & ~static_cast<uint32_t>(0xffff << m_shift)) | (value << m_shift);
return *this;
}
};
int main() {
uint32_t data = 0x01020304;
Uint32BitView16 v1(data, 0);
Uint32BitView16 v2(data, 16);
std::cout << std::hex;
std::cout << static_cast<uint16_t>(v1) << '\n'; // 304
std::cout << static_cast<uint16_t>(v2) << '\n'; // 102
data = 0xffff0000;
std::cout << static_cast<uint16_t>(v1) << '\n'; // 0
std::cout << static_cast<uint16_t>(v2) << '\n'; // ffff
v1 = 0xff;
std::cout << data << '\n'; // ffff00ff
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论