在C 中使用uint8_tover有什么好处unsigned char?
我知道几乎每个系统uint8_t都只是一个typedef unsigned char,为什么要用呢?
我最近遇到了一个奇怪的去优化(或者错过了优化机会).
考虑此函数可以有效地将3位整数数组解包为8位整数.它在每次循环迭代中解包16个int:
void unpack3bit(uint8_t* target, char* source, int size) {
while(size > 0){
uint64_t t = *reinterpret_cast<uint64_t*>(source);
target[0] = t & 0x7;
target[1] = (t >> 3) & 0x7;
target[2] = (t >> 6) & 0x7;
target[3] = (t >> 9) & 0x7;
target[4] = (t >> 12) & 0x7;
target[5] = (t >> 15) & 0x7;
target[6] = (t >> 18) & 0x7;
target[7] = (t >> 21) & 0x7;
target[8] = (t >> 24) & 0x7;
target[9] = …Run Code Online (Sandbox Code Playgroud) c++ optimization strict-aliasing compiler-optimization c++11
现在我们有时必须使用二进制数据.在C++中,我们使用字节序列,因为开头char是我们的构建块.定义为sizeof1,它是字节.char默认情况下,所有库I/O函数都使用.一切都很好,但总是有一点担心,有点奇怪,一些人的错误 - 一个字节中的位数是实现定义的.
所以在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_t二进制数据.或许,我们中的一些人不关心字节中的位数并且对它感到满意.
但遗憾的是,两个世界相互冲突,有时您必须将数据作为char*并将其传递给期望的库std::uint8_t*.但是等等,你说,是不是char变量位并std::uint8_t固定为8?它会导致数据丢失吗?
嗯,这里有一个有趣的标准.的char定义为保持正好一个字节和字节是内存的最低可寻址的块,所以用比特宽度比的较小不能有一个类型char.接下来,它被定义为能够保存UTF-8代码单元.这给了我们最小--8位.所以现在我们有一个typedef,它要求是8位宽,并且是一个至少8位宽的类型.但有其他选择吗?是的,unsigned char.请记住,签名char是实现定义的.还有其他任何一种 谢天谢地,没有.所有其他整数类型都需要超出8位的范围.
最后,std::uint8_t是可选的,这意味着如果未定义使用此类型的库将无法编译.但如果它编译呢?我可以非常自信地说,这意味着我们在8位字节的平台上CHAR_BIT == 8.
一旦我们有这方面的知识,我们已经8位字节,这std::uint8_t是实现为char或者unsigned char,我们可以假设,我们可以做reinterpret_cast的char*到std::uint8_t*,反之亦然?它是便携式的吗?
这是我的Standardese阅读技巧让我失望的地方.我读了关于安全派生的指针([basic.stc.dynamic.safety]),据我所知,以下内容:
std::uint8_t* buffer = /* ... */ ;
char* buffer2 …Run Code Online (Sandbox Code Playgroud) 如果 along int和 aint在平台上的表示相同,它们是否严格相同?根据 C 标准,这些类型在平台上的行为是否有任何不同?
例如。这是否总是有效:
int int_var;
long long_var;
void long_bar(long *l);
void int_bar(int *i);
void foo()
{
long_bar(&int_var); /* Always OK? */
int_bar(&long_var);
}
Run Code Online (Sandbox Code Playgroud)
我想同样的问题适用于 short 和 int,如果它们碰巧是相同的表示。
在讨论如何为int32_t没有 stdint.h 的嵌入式 C89 编译器定义一个-like typedef时出现了问题,即 as intorlong以及是否重要。
我的理解是,uint8_t从a 中读取stringstream是一个问题,因为stringstream它将把它解释uint8_t为a char.我想知道如何uint8_t从stringstream一个数字类型中读取a .例如,以下代码:
#include <iostream>
#include <sstream>
using namespace std;
int main()
{
uint8_t ui;
std::stringstream ss("46");
ss >> ui;
cout << unsigned(ui);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
打印出来52.我想打印出来46.
编辑:另一种做法只是读取string距离stringstream,然后转换解决方案uint8_t,但是这打破了很好的链接属性.例如,在我必须编写的实际代码中,我经常需要这样的东西:
void foobar(std::istream & istream){
uint8_t a,b,c;
istream >> a >> b >> c;
// TODO...
}
Run Code Online (Sandbox Code Playgroud) 我最近问了这个问题:
问题是我正在写一个类型的数组,uint8_t并且编译器将它视为可以使用this方法的指针(类型struct T*)进行别名,因为void*和char*(= uint8_t*)总是可以在C++中对任何其他指针进行别名.此行为导致错过优化机会.当然,我想避免这种情况.所以问题是:我是否可以声明一个uint8_t强制执行严格别名的数组,即编译器将其视为从不与另一种类型的指针混淆?也就是说,我在寻找的东西像一个strict_uint8_t类型,它是一种uint8_t具有特殊混淆的行为.有没有办法实现这个目标?
显示我的意思的示例代码,借用其他问题并简化.有关更多详细信息,请阅读链接的问题及其接受的答案:
struct T{
uint8_t* target;
void unpack3bit(char* source, int size) {
while(size > 0){
uint64_t t = *reinterpret_cast<uint64_t*>(source);
/** `this->target` cannot be cached in a register here but has
to be reloaded 16 times because the compiler
thinks that `this->target` could alias with `this` itself.
What I want is a special uint8_t type that does not trigger
this …Run Code Online (Sandbox Code Playgroud) 问题:
是否存在任何c ++工具链,std::uint8_t但不是unsigned char(或者char,如果它是无符号的)的typedef ?
编辑:相反:在符合标准的实施中,这样的事情是否可能?
背景/动机:
我主要是因为我想知道是否std::uint8_t*可以移植来访问单个字节(就像unsigned char*).是的,我知道std::byte,但这不相关.我主要对x86,arm和mips的工具链感兴趣,但出于好奇,我也想听听其他的例子.
我没有找到与搜索直接相关的任何内容,所以请原谅这是否重复.
我想要做的是通过网络连接序列化数据.我的方法是将我需要传输的所有内容转换std::vector< uint8_t >为接收方并将数据解压缩到适当的变量中.我的方法如下:
template <typename T>
inline void pack (std::vector< uint8_t >& dst, T& data) {
uint8_t * src = static_cast < uint8_t* >(static_cast < void * >(&data));
dst.insert (dst.end (), src, src + sizeof (T));
}
template <typename T>
inline void unpack (vector <uint8_t >& src, int index, T& data) {
copy (&src[index], &src[index + sizeof (T)], &data);
}
Run Code Online (Sandbox Code Playgroud)
我正在使用它
vector< uint8_t > buffer;
uint32_t foo = 103, bar = 443;
pack (buff, foo);
pack (buff, …Run Code Online (Sandbox Code Playgroud) 我想要一个类型,如下所示unsigned char:
但是,与 不同的是unsigned char,它不允许使用别名。我的意思是,一种没有例外的类型[basic.lval/11.8]:
\n\n\n如果程序尝试通过以下类型之一以外的泛左值访问对象的存储值,则行为未定义:
\n\n[...]
\n\n\n
\n- 一个 char,无符号字符或 std\xe2\x80\x8b::\xe2\x80\x8bbyte 类型。
\n
有可能有这样的类型吗?
\n\n原因是:我几乎从不使用unsigned char\ 的别名属性。因此,我想使用一种类型,它不会阻止某些类型的优化(注意,我问这个问题是因为我实际上有一些函数,由于允许别名,因此没有很好地优化)的财产unsigned char)。因此,我希望有一种类型能够满足这一点:“不要为不使用的东西付费”。
这是一个unsigned char阻止优化的示例:使用此指针会导致热循环中奇怪的去优化
我有一个浮点数组(每个浮点数4个字节),我想将数据复制到一个字节数组(uint8_t)并将其视为字节.后来我可能想要将字节数据复制回浮点数组,并将其再次作为各种操作的浮点数处理.这在c ++中有效吗?换句话说,就像这样,我暂时将浮点数视为字节有效?
std::array<std::uint8_t, 40> b;
b.fill(0);
std::array<float,10> f;
f.fill(3.14);
std::memcpy(b.data(),f.data(),40);
std::array<float,10> f2;
f2.fill(0);
std::memcpy(f2.data(),b.data(),40);
for(std::size_t i=0;i<10;i++)
{
std::cout<<f2[i]<<std::endl; //now i want to access the float data
}
Run Code Online (Sandbox Code Playgroud) 作为使用 React Native 的移动开发人员,我需要使用创建和加密文件的 C++ 代码。我对 C++ 没有太多经验(我上次写一些东西已经是 15 年前在大学时的事了)。
如果我错了,请纠正我。
这让我很烦恼。这是文件的类型定义:
typedef struct File
{
uint8_t FileName[64];
uint8_t userName[64];
}File;
Run Code Online (Sandbox Code Playgroud)
为什么要使用类型uint8_t来存储字符串而不是std::string?
后来,事情变得更加扑朔迷离。我们需要将所有字符一一解析出来,并写入到临时文件中。
#define FILE_NAME_LEN 64
CustomFile CFile::getCustomFileFromFile(tFile f_File)
{
CustomFile returnValue;
for(int i = 0;i<FILE_NAME_LEN;i++){
returnValue.FileName[i] = f_File.FileName[i];
}
for(int i = 0;i<FILE_NAME_LEN;i++){
returnValue.user_name[i] = f_File.user_name[i];
}
return returnValue;
}
bool WriteEncryptFile(QString fpath,tFile *p_tFile)
{
// Convert the tFile object to a CustomFile object
CustomFile customFile = CFile::getCustomFileFromFile(*p_tFile);
}
Run Code Online (Sandbox Code Playgroud) 假设我有一个枚举,它只包含最多 0xFF 的值。我想将该枚举值放入一个字节变量中。AFAIK 枚举int位于 (vxWorks) 下方。我正在编码的机器是大端。当我想将它放入 uint8_t 时,我不明白这是否重要。这些选项中哪些有效,哪些是最好的?
typedef enum {
kEnum1 = 0x00,
kEnum2 = 0x01,
kEnum3 = 0xFF
} MyEnum;
MyEnum myenum = kEnum3;
uint8_t mybyte = 0;
// option 1, do nothing
mybyte = myenum ;
// option 2, explicit cast
mybyte = (uint8_t)myenum;
// option 3, use operators
mybyte = (myenum & 0xFF000000) >> 24;
Run Code Online (Sandbox Code Playgroud)
当我在一个我认为是小端的在线编译器上测试时,选项 3 当然不起作用。但其他人会。我只是不明白大端机器将如何对待这些选项。