How to use new std::byte type in places where old-style unsigned char is needed?
You're missing the point why std::byte
was invented in the first place. The reason it was invented is to hold a raw byte in memory without the assumption that it's a character. You can see that in cppreference.
Like char and unsigned char, it can be used to access raw memory occupied by other objects (object representation), but unlike those types, it is not a character type and is not an arithmetic type.
Remember that C++ is a strongly typed language in the interest of safety (so implicit conversions are restricted in many cases). Meaning: If an implicit conversion from byte
to char
was possible, it would defeat the purpose.
So, to answer your question: To use it, you have to cast it whenever you want to make an assignment to it:
std::byte x = (std::byte)10;
std::byte y = (std::byte)'a';
std::cout << (int)x << std::endl;
std::cout << (char)y << std::endl;
Anything else shall not work, by design! So that transform is ugly, agreed, but if you want to store chars, then use char
. Don't use bytes unless you want to store raw memory that should not be interpreted as char
by default.
And also the last part of your question is generally incorrect: You don't have to make copies, because you don't have to copy the whole vector. If you temporarily need to read a byte
as a char
, simply static_cast
it at the place where you need to use it as a char
. It costs nothing, and is type-safe.
As to your question in the comment about casting
std::vector<char>
to std::vector<std::byte>
, you can't do that. But you can use the raw array underneath. So, the following has a type (char*)
:std::vector<std::byte> bytes;
// fill it...
char* charBytes = reinterpret_cast<char*>(bytes.data());
This has type char*
, which is a pointer to the first element of your array, and can be dereferenced without copying, as follows:
std::cout << charBytes[5] << std::endl; //6th element of the vector as char
And the size you get from bytes.size()
. This is valid, since std::vector
is contiguous in memory. You can't generally do this with any other std container (deque, list, etc...).
While this is valid, it removes part of the safety from the equation, keep that in mind. If you need char
, don't use byte
.
How convert std::vectorstd::byte to C-style raw data(unsigned char**)?
To provide a vector<char>
to a C function accepting const char**
you can access the internal buffer and return a pointer to it:
#include <iostream>
#include <vector>
void someCApi(const char** c, size_t len)
{
for (size_t i=0; i<len; ++i)
{
std::cout << static_cast<int>((*c)[i]) << std::endl;
}
}
auto main() -> int
{
std::vector<char> buff{1,3,5,7,11,13,17,19};
const char* buffPtr = buff.data();
someCApi(&buffPtr, buff.size());
return 0;
}
https://onlinegdb.com/B1BSNKyrv
Simple interface to get the pointer to array:
template <typename T>
class pptr
{
const T* buff=nullptr;
public:
ppta(std::vector<T>& v): buff(v.data()){};
const T** operator()(){return &buff;}
};
//Usage
someCApi(pptr(buff)(), buff.size());
Is there a legal way to convert a unsigned char pointer to std::byte pointer?
The strict aliasing rule never forbids any pointer conversions. It is about the type of an expression accessing an object.
std::byte
may alias any other type, this is mentioned in the cppreference page you linked, as well as in the strict aliasing rule in the Standard of course (C++17 basic.lval/8.8). So it is fine to use reinterpret_cast<std::byte *>
and then read or write the array of unsigned char
.
If you use an expression of type uint32_t
to read or write an array of unsigned char
, that would violate the strict aliasing rule.
What is the purpose of std::byte?
You are perhaps misunderstanding things.
byte
is very much intended for "accessing memory". You are intended to use the type when the storage is just a sequence of bytes rather than an array of characters.
Iostream types cannot be specialized with byte
, since they're designed around characters as their interface. That is, they do not think of files as sequences of bytes; they think of them as sequences of characters. Now, you can certainly read directly into a byte
array by using a cast or two. But that's not the way iostream natively thinks.
You have to make a distinction between the way iostream works and the way files work. Iostream is just one file IO library, after all; it is hardly the end-all, be-all of file APIs.
Most file APIs for reading binary data take void*
rather than character arrays. std::fread/fwrite
, and so forth.
That is, you should think of this, not as a problem with std::byte
, but as a problem with iostream. Just another in a long line of them.
How to use something like `std::basic_istreamstd::byte`
Don't.
Whether you're operating in "text mode" or "binary mode", what you are still doing fundamentally is acting on characters.
std::byte
is not for this purpose, and that's why it does not have these features. Indeed, it was deliberately introduced not to have them!
enum class byte : unsigned char {} ;
(since C++17)
std::byte
is a distinct type that implements the concept of byte as specified in the C++ language definition.Like
char
andunsigned char
, it can be used to access raw memory occupied by other objects (object representation), but unlike those types, it is not a character type and is not an arithmetic type. A byte is only a collection of bits, and only bitwise logic operators are defined for it.http://en.cppreference.com/w/cpp/types/byte
Did anyone make this kind of thing work already?
No, everyone deliberately didn't, as explored above.
Use char
or unsigned char
, as we have done for decades!
Why is there no overload for printing `std::byte`?
From the paper on std::byte
(P0298R3): (emphasis mine)
Design Decisions
std::byte
is not an integer and not a characterThe key motivation here is to make byte a distinct type – to improve program safety by leveraging the type system. This leads to the design that
std::byte
is not an integer type, nor a character type. It is a distinct
type for accessing the bits that ultimately make up object storage.
As such, it is not required to be implicitly convertible/interpreted to be either a char
or any integral type whatsoever and hence cannot be printed using std::cout
unless explicitly cast to the required type.
Furthermore, this question might help.
How to convert std::string to std::vectorstd::byte in C++17?
Using std::transform
should work:
#include <algorithm>
#include <cstddef>
#include <iostream>
#include <vector>
int main()
{
std::string gpsValue;
gpsValue = "time[.........";
std::vector<std::byte> gpsValueArray(gpsValue.size() + 1);
std::transform(gpsValue.begin(), gpsValue.end(), gpsValueArray.begin(),
[] (char c) { return std::byte(c); });
for (std::byte b : gpsValueArray)
{
std::cout << int(b) << std::endl;
}
return 0;
}
Output:
116
105
109
101
91
46
46
46
46
46
46
46
46
46
0
How to use interfaces that expect `const char*` if I'm working with `std::byte`s
Given a contiguous buffer of std::byte
s, a reinterpretation of a std::byte*
to a char*
is legal by design and doesn't violate the strict aliasing rule:
(wording from the most recent revision of the std::byte
proposal)
Lvalues and rvalues [basic.lval]
If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
[...]
(8.8) a
char
,unsigned char
, orstd::byte
type.
(note: the "or std::byte
" is added by the proposal)
So you can use reinterpret_cast<const char*>(pointer_to_std_byte_buffer)
or static_cast<const char*>(static_cast<const void*>(pointer_to_std_byte_buffer))
or (const char*)pointer_to_std_byte_buffer
, depending on what your style guide says.
Related Topics
Copying Derived Entities Using Only Base Class Pointers, (Without Exhaustive Testing!) - C++
How to Pack a Visual Studio C++ Project for Release
C++ Most Efficient Way to Convert String to Int (Faster Than Atoi)
Getting a Directory Name from a Filename
Element at Index in a Std::Set
How to Access MySQL from Multiple Threads Concurrently
How to Use Sendinput Function C++
How to Write the Following as a C++ MACro
What Is a Good Easy to Use Profiler for C++ on Linux
Openmp Nested Parallel for Loops VS Inner Parallel For
C++11 Emplace_Back on Vector<Struct>
Check the File-Size Without Opening File in C++
Increment Void Pointer by One Byte? by Two
Is 'Bool' a Basic Datatype in C++