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?
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.
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
}
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
}
Related
I have the following definitions:
struct Display_font_char
{
unsigned char * data;
int originX;
int originY;
unsigned int width;
unsigned int height;
unsigned int delta;
};
struct Display_font
{
Display_font_char * chars;
unsigned char rangeStart;
unsigned char rangeEnd;
};
How can I initialize it inplace? I'm trying:
const Display_font font =
{
{
{
{ 1, 2, 3 },
1,
2,
3u,
4u,
5u
}
},
1u,
2u
}
However, I'm getting an error: "Cannot use value of type int to initialize field of type Display_font_char *"
You cannot initialise a pointer with a braced init list of multiple values.
Here is an example of how you could initialise an instance of the class:
unsigned char uc[] = { 1, 2, 3 };
Display_font_char fc {
uc,
1,
2,
3u,
4u,
5u,
};
const Display_font font =
{
&fc,
1u,
2u,
};
As a sidenote, if you were to switch to C, then you could use compound literals:
const struct Display_font font =
{
&(struct Display_font_char){
(unsigned char []){ 1, 2, 3 },
1,
2,
3u,
4u,
5u
},
1u,
2u
};
But alas, compound literals don't exist in C++.
In order to initialize your pointers, you have to create the pointed structures first, for example using new.
Notice that, if you want to treat Display_font.chars and Display_font_char.data as arrays, you should save their sizes (e.g. through a size_t data_size member).
In the example below I create the arrays with new[] and I delete them later on with delete[].
[Demo]
#include <iostream> // cout
#include <ostream>
struct Display_font_char
{
unsigned char* data;
size_t data_size;
int originX;
int originY;
unsigned int width;
unsigned int height;
unsigned int delta;
};
std::ostream& operator<<(std::ostream& os, const Display_font_char& f)
{
os << "\tdata = [";
for (size_t i{0}; i < f.data_size; ++i)
{
os << ((i == 0) ? "" : ", ") << static_cast<int>(f.data[i]);
}
os << "]\n";
os << "\toriginX = " << f.originX << "\n";
os << "\toriginY = " << f.originY << "\n";
os << "\twidth = " << f.width << "\n";
os << "\theight = " << f.height << "\n";
os << "\tdelta = " << f.delta << "\n";
return os;
}
struct Display_font
{
Display_font_char* chars;
size_t chars_size;
unsigned char rangeStart;
unsigned char rangeEnd;
};
std::ostream& operator<<(std::ostream& os, const Display_font& f)
{
os << "chars = [\n";
for (size_t i{0}; i < f.chars_size; ++i)
{
os << ((i == 0) ? "" : ", ") << f.chars[i];
}
os << "]\n";
os << "rangeStart = " << static_cast<int>(f.rangeStart) << "\n";
os << "rangeEnd = " << static_cast<int>(f.rangeEnd) << "\n";
return os;
}
int main()
{
const Display_font font = {
new Display_font_char[1]{
new unsigned char[4]{1, 2, 3},
3, // data size
1, 2,
3u, 4u, 5u
},
1, // chars size
1, 2
};
std::cout << font;
delete[] font.chars[0].data;
delete[] font.chars;
}
This other version uses std::vector instead of Display_font_char* and unsigned char*, so you don't have to do care about memory allocations/deallocations.
[Demo]
#include <iostream> // cout
#include <ostream>
#include <vector>
struct Display_font_char
{
std::vector<unsigned char> data;
int originX;
int originY;
unsigned int width;
unsigned int height;
unsigned int delta;
};
std::ostream& operator<<(std::ostream& os, const Display_font_char& f)
{
os << "\tdata = [";
bool first{true};
for (auto& d : f.data)
{
os << (first ? "" : ", ") << static_cast<int>(d);
first = false;
}
os << "]\n";
os << "\toriginX = " << f.originX << "\n";
os << "\toriginY = " << f.originY << "\n";
os << "\twidth = " << f.width << "\n";
os << "\theight = " << f.height << "\n";
os << "\tdelta = " << f.delta << "\n";
return os;
}
struct Display_font
{
std::vector<Display_font_char> chars;
unsigned char rangeStart;
unsigned char rangeEnd;
};
std::ostream& operator<<(std::ostream& os, const Display_font& f)
{
os << "chars = [\n";
bool first{true};
for (auto& c : f.chars)
{
os << (first ? "" : ", ") << c;
first = false;
}
os << "]\n";
os << "trangeStart = " << static_cast<int>(f.rangeStart) << "\n";
os << "rangeEnd = " << static_cast<int>(f.rangeEnd) << "\n";
return os;
}
int main()
{
const Display_font font{
{ { {1, 2, 3}, 1, 2, 3u, 4u, 5u } },
1,
2
};
std::cout << font;
}
I'm unable to have this code running properly on Ubuntu 20.04 (gcc), and I'm only able to have the template deducted for the else branch (integers), ignoring all the deductions for bool, double and std:string
I even tried the std::enable_if but to no avail...
What am I'm missing here?
#include <iostream>
#include <string>
#include <cstdint>
namespace myns
{
using UInt64 = uint64_t;
using Int64 = int64_t;
using UInt32 = uint32_t;
using Int32 = int32_t;
using UInt16 = uint16_t;
using Int16 = int16_t;
using UInt8 = uint8_t;
using Int8 = int8_t;
}
bool function_int (myns::UInt64& i)
{
i = 10;
}
bool function_float (double& d)
{
d = 4.3;
}
bool function_bool (bool& b)
{
b = true;
}
bool function_str(std::string& s)
{
s = "Hello World";
}
template <typename T>
bool function(T&& value)
{
if constexpr (std::is_same_v<T, bool>)
{
std::cout << "Returning bool" << std::endl;
return function_bool (std::forward<T> (value));
}
else if constexpr (std::is_same_v<T, double>)
{
std::cout << "Returning double" << std::endl;
return function_float (std::forward<T> (value));
}
else if constexpr (std::is_same_v<T, std::string>)
{
std::cout << "Returning string" << std::endl;
return function_str (std::forward<T> (value));
}
else
{
std::cout << "Returning integer" << std::endl;
myns::UInt64 val;
auto ret = function_int (val);
value = val;
}
}
using namespace myns;
int main()
{
UInt64 ui64;
Int64 i64;
UInt32 ui32;
Int32 i32;
UInt16 ui16;
Int16 i16;
UInt8 ui8;
Int8 i8;
std::string str;
bool boolean;
double dbl;
function(str);
function(ui64);
function(i64);
function(ui32);
function(i32);
function(ui16);
function(i16);
function(ui8);
function(i8);
function(boolean);
function(dbl);
std::cout << "Uint64: " << ui64 << std::endl;
std::cout << "Int64: " << i64 << std::endl;
std::cout << "UInt32: " << ui32 << std::endl;
std::cout << "Int32: " << i32 << std::endl;
std::cout << "UInt16: " << ui16 << std::endl;
std::cout << "Int16: " << i16 << std::endl;
std::cout << "UInt8: " << ui8 << std::endl;
std::cout << "Int8: " << i8 << std::endl;
std::cout << "String: " << str << std::endl;
std::cout << "bool: " << boolean << std::endl;
std::cout << "double: " << dbl << std::endl;
}
Output:
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Returning integer
Uint64: 10
Int64: 10
UInt32: 10
Int32: 10
UInt16: 10
Int16: 10
UInt8:
Int8:
String:
bool: 1
double: 10
I've been banging my head for almost a day with no solutions on site, I even though of giving up and creating a template specialization for all the types, but I this is a lot of code "repetition" that could be all done in a small template
Thanks in advance!
T is being deduced as a reference here. For example, when invoked with a double, the argument is double & && (which collapses to double &). T is double &, which is not the same thing as double. std::is_same_v<double &, double> is indeed false.
One solution would be to remove any reference from T before checking:
std::is_same_v<std::remove_reference_t<T>, double>
Side note: you have several functions returning bool but without any return statement. This causes undefined behavior.
Thanks to #cdhowie the proper code should be like the one below
#include <iostream>
#include <string>
#include <cstdint>
namespace myns
{
using UInt64 = uint64_t;
using Int64 = int64_t;
using UInt32 = uint32_t;
using Int32 = int32_t;
using UInt16 = uint16_t;
using Int16 = int16_t;
using UInt8 = uint8_t;
using Int8 = int8_t;
}
bool function_int (myns::UInt64& i)
{
i = 10;
}
bool function_float (double& d)
{
d = 4.3;
}
bool function_bool (bool& b)
{
b = true;
}
bool function_str(std::string& s)
{
s = "Hello World";
}
template <typename T>
bool function(T&& value)
{
if constexpr (std::is_same_v<std::remove_reference_t<T>, bool>)
{
std::cout << "Returning bool" << std::endl;
return function_bool (std::forward<T> (value));
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, double>)
{
std::cout << "Returning double" << std::endl;
return function_float (std::forward<T> (value));
}
else if constexpr (std::is_same_v<std::remove_reference_t<T>, std::string>)
{
std::cout << "Returning string" << std::endl;
return function_str (std::forward<T> (value));
}
else
{
std::cout << "Returning integer" << std::endl;
myns::UInt64 val;
auto ret = function_int (val);
value = val;
return value;
}
}
using namespace myns;
int main()
{
UInt64 ui64;
Int64 i64;
UInt32 ui32;
Int32 i32;
UInt16 ui16;
Int16 i16;
UInt8 ui8;
Int8 i8;
std::string str;
bool boolean;
double dbl;
// Ignore the return values, this is just for prototyping..
function(str);
function(ui64);
function(i64);
function(ui32);
function(i32);
function(ui16);
function(i16);
function(ui8);
function(i8);
function(boolean);
function(dbl);
std::cout << "Uint64: " << ui64 << std::endl;
std::cout << "Int64: " << i64 << std::endl;
std::cout << "UInt32: " << ui32 << std::endl;
std::cout << "Int32: " << i32 << std::endl;
std::cout << "UInt16: " << ui16 << std::endl;
std::cout << "Int16: " << i16 << std::endl;
std::cout << "UInt8: " << ui8 << std::endl;
std::cout << "Int8: " << i8 << std::endl;
std::cout << "String: " << str << std::endl;
std::cout << "bool: " << boolean << std::endl;
std::cout << "double: " << dbl << std::endl;
}
Normally it has no sense and is very unsafe, but only theoretically if there is a way,
Here is example:
#include<iostream>
struct A {
uint32_t &get() {
return *reinterpret_cast<uint32_t *>(this);
}
void set(const uint32_t val) {
*this = *reinterpret_cast<const A *>(&val);
}
};
struct B : A {
uint16_t a;
uint16_t b;
void set_b(const uint32_t val) {
*this = *reinterpret_cast<const B *>(&val);
}
};
main() {
B k;
k.a = 0x1234;
k.b = 0x5678;
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set_b(0x87654321);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
k.set(0xaabbccdd);
std::cout << std::hex << k.get() << " : " << k.a << " " << k.b << std::endl;
}
I get this result:
56781234 : 1234 5678
87654321 : 4321 8765
87654321 : 4321 8765
But I except that last should be:
aabbccdd : ccdd aabb
So, why overwriting data in structure from parent not working?
Experiment:
I make one experiment, that I add one variable into struct A, then set function was working as expected (but final structure was bigger)
Of course there exists different ways how to deal with this (for example with unions) but I only playing with this and I interested why this is not working.
In the class A the set function is really
void set(const uint32_t val) {
(*this).operator=(*reinterpret_cast<const A *>(&val));
}
That will invoke the automatically generated A::operator= function. But since A doesn't have any member variables to be copied, it does nothing.
And now that you've done your experiment, please don't do anything like that ever again.
I am working on some low level code with high level interfaces and felt need for comparisons operator for unit testing for plain old data types(like FILETIME struct) but since C++ doesn't even provide memberwise comparisons, so I wrote this:
template <typename Type>
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b) {
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
So my question is, is this a good way or there are some hidden demons which will give me trouble later down the development cycle but it's kinda working for now.
Is C++14 available? If so, consider PFR library, which makes structures into tuples
This question is a restricted variant of Define generic comparison operator, as noted in the comments. An example of the dangers and effects of padding on the proposed operator== for POD is:
template <typename Type>
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b)
{
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
struct St {
bool a_bool;
int an_int;
};
union Un {
char buff[sizeof(St)];
St st;
};
std::ostream &operator<<(std::ostream & out, const St& data)
{
return out << '{' << std::boolalpha << data.a_bool << ", " << data.an_int << '}';
}
int main()
{
Un un{{1,2,3,4,5}};
new (&un.st) St;
un.st.a_bool = true;
un.st.an_int = 5;
St x={true, 5};
std::cout << "un.a=" << un.st << '\n';
std::cout << "x=" << x << '\n';
std::cout << (x == un.st) << "\n";
return 0;
}
Both un.st and x contain the same data, but un.st contains some garbage in the padded bytes. The padded garbage makes the propose operator== return false for logically equivalent objects. Here is the output I have got for both gcc (head-9.0.0) and clang (head-8.0.0):
un.a={true, 5}
x={true, 5}
false
Update: this happens also with regular new/delete, as run on wandbox.org:
std::enable_if_t<std::is_pod<Type>::value, bool> operator==(const Type& a,
const Type& b)
{
return std::memcmp(&a, &b, sizeof(Type)) == 0;
}
struct St {
bool a_bool;
int an_int;
};
std::ostream &operator<<(std::ostream & out, const St& data)
{
return out << '{' << std::boolalpha << data.a_bool << ", " << data.an_int << '}';
}
static constexpr unsigned N_ELEMENTS = 2;
int main()
{
{
volatile char * arr = new char[sizeof(St) * N_ELEMENTS];
for (unsigned i=0; i < sizeof(St) * N_ELEMENTS ; ++i)
arr[i] = i + 1;
std::cout << "arr = " << (void*)arr << "\n";
delete[] arr;
}
St * ptr_st = new St[N_ELEMENTS];
std::cout << "ptr_st = " << ptr_st << "\n";
for (unsigned i=0 ; i != N_ELEMENTS; ++i) {
ptr_st[i].a_bool = true;
ptr_st[i].an_int = 5;
}
St x={true, 5};
std::cout << "x=" << x << '\n';
std::cout << "ptr_st[1]=" << ptr_st[1] << '\n';
std::cout << (x == ptr_st[1]) << "\n";
return 0;
}
For which the output is:
arr = 0x196dda0
ptr_st = 0x196dda0
x={true, 5}
ptr_st[1]={true, 5}
false
This question already has answers here:
How can I print 0x0a instead of 0xa using cout?
(9 answers)
Closed 6 years ago.
Say I have a dword I want to output in hex with std::cout and left-pad with zeros, so 0xabcd will be shown as 0x0000abcd. It seems like you would have to do this:
uint32_t my_int = 0xabcd;
std::cout << "0x" << std::hex << std::setw(8) << std::setfill('0')
<< my_int << std::endl;
This seems ridiculous for something that can be accomplished in C with printf("0x%08X\n", my_int);. Is there any way to make this shorter while still using std::cout for output (besides using namespace std)?
I suppose you can write a "stream manipulator". This is useful if you have multiple hex numbers you want to print in this format. This is clearly not an ideal solution, but using a wrapper type you can make your own "format flag" to toggle it. See Sticky custom stream manipulator for more information.
#include <iostream>
#include <iomanip>
static int const index = std::ios_base::xalloc();
std::ostream& hexify(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}
std::ostream& nohexify(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}
struct WrapperType {
uint32_t _m;
public:
WrapperType(uint32_t m) : _m(m)
{
}
uint32_t getm() const
{
return _m;
}
};
std::ostream& operator<< (std::ostream& os, const WrapperType& t) {
if (os.iword(index))
return os << "0x" << std::hex << std::setw(8) << std::setfill('0') << t.getm();
else
return os << t.getm();
}
int main()
{
WrapperType my_int{0xabcd};
std::cout << hexify << my_int << my_int;
std::cout << nohexify << my_int;
}
I would not change the (global) flags of a stream, just a manipulator:
#include <iostream>
#include <iomanip>
#include <limits>
template <typename T>
struct Hex
{
// C++11:
// static constexpr int Width = (std::numeric_limits<T>::digits + 1) / 4;
// Otherwise:
enum { Width = (std::numeric_limits<T>::digits + 1) / 4 };
const T& value;
const int width;
Hex(const T& value, int width = Width)
: value(value), width(width)
{}
void write(std::ostream& stream) const {
if(std::numeric_limits<T>::radix != 2) stream << value;
else {
std::ios_base::fmtflags flags = stream.setf(
std::ios_base::hex, std::ios_base::basefield);
char fill = stream.fill('0');
stream << "0x" << std::setw(width) << value;
stream.fill(fill);
stream.setf(flags, std::ios_base::basefield);
}
}
};
template <typename T>
inline Hex<T> hex(const T& value, int width = Hex<T>::Width) {
return Hex<T>(value, width);
}
template <typename T>
inline std::ostream& operator << (std::ostream& stream, const Hex<T>& value) {
value.write(stream);
return stream;
}
int main() {
std::uint8_t u8 = 1;
std::uint16_t u16 = 1;
std::uint32_t u32 = 1;
std::cout << hex(unsigned(u8), 2) << ", " << hex(u16) << ", " << hex(u32) << '\n';
}
My C++ is rusty, but how about using Boost formatting: http://www.boost.org/doc/libs/1_37_0/libs/format/index.html