char是1个字节,整数是4个字节.我想逐字节地从char [4]复制到整数.我想到了不同的方法,但我得到了不同的答案.
char str[4]="abc";
unsigned int a = *(unsigned int*)str;
unsigned int b = str[0]<<24 | str[1]<<16 | str[2]<<8 | str[3];
unsigned int c;
memcpy(&c, str, 4);
printf("%u %u %u\n", a, b, c);
Run Code Online (Sandbox Code Playgroud)
输出为6513249 1633837824 6513249
哪一个是正确的?出了什么问题?
我怎样才能最好地转换uint32_t成int32_t快速地与包装,在C++?
一些尝试:
uint32_t y = UINT32_MAX;
int32_t x = (int32_t)y; // UB on overflow
int32_t x = *(int32_t*)&y; // does this violate strict aliasing?
Run Code Online (Sandbox Code Playgroud) 我有一个程序需要占用4个字节并将它们转换为IEEE-754浮点数.字节不按顺序传输,但我可以把它们按顺序放回去.我的问题是把它们扔到浮子上.代码的相关部分:
//Union to store bytes and float on top of each other
typedef union {
unsigned char b[4];
float f;
} bfloat;
//Create instance of the union
bfloat Temperature;
//Add float data using transmitted bytes
MMI.Temperature.b[2] = 0xD1;//MMIResponseMsg[7];
MMI.Temperature.b[3] = 0xE1;//MMIResponseMsg[8];
MMI.Temperature.b[0] = 0x41;//MMIResponseMsg[9];
MMI.Temperature.b[1] = 0xD7;//MMIResponseMsg[10];
//Attempting to read the float value
lWhole=(long) ((float)MMI.Temperature.f);
//DEBUGGING
stevenFloat = (float)MMI.Temperature.f;
Run Code Online (Sandbox Code Playgroud)
lWhole很长,stevenFloat是一个漂浮.当调试我可以看到,我分配给字节数组中的值被正确地存储,然而的值stevenFloat和lWhole不正确.它们似乎悬停在接近0或接近最大浮点数/长值的位置.使用我的编译器,long和float都是32位.
有谁知道为什么这不起作用?当我收到要处理的代码时看起来对我来说是正确的,它似乎是一个在线的常见解决方案,我只是难倒.
我们发现要替换的各种技巧std::sqrt(Timing Square Root)和一些std::exp(使用更快的指数近似),但我找不到任何可替代的东西std::log.
它是我程序中循环的一部分,它被多次调用,而exp和sqrt被优化,英特尔VTune现在建议我进行优化std::log,之后似乎只有我的设计选择才会受到限制.
现在我使用的第三阶泰勒近似ln(1+x)与x之间-0.5和+0.5(对于4%最大误差的情况下的%90)和回退到std::log否则.这让我加速了15%.
我一直在努力寻找一种可移植的方法来序列化C和C++中的32位浮点变量,以便发送到微控制器和从微控制器发送.我希望格式足够明确,以便可以从其他语言完成序列化/反序列化,而无需太多努力.相关问题是:
我知道在大多数情况下,类型转换联合/ memcpy可以正常工作,因为浮动表示是相同的,但我宁愿有更多的控制和心灵.到目前为止我想出的是以下内容:
void serialize_float32(uint8_t* buffer, float number, int32_t *index) {
int e = 0;
float sig = frexpf(number, &e);
float sig_abs = fabsf(sig);
uint32_t sig_i = 0;
if (sig_abs >= 0.5) {
sig_i = (uint32_t)((sig_abs - 0.5f) * 2.0f * 8388608.0f);
e += 126;
}
uint32_t res = ((e & 0xFF) << 23) | (sig_i & 0x7FFFFF);
if (sig < 0) {
res |= 1 << 31;
}
buffer[(*index)++] = (res …Run Code Online (Sandbox Code Playgroud) 我能够打印出int的地址和值,但不能打印出union的字符.为什么会这样
#include <iostream>
using namespace std;
union Endian
{
int i;
char c[sizeof(int)];
int j;
};
int main(int argc, char *argv[]) {
Endian e;
e.i = 20;
cout << &e.j;
cout << &e.i;
cout << &e.c[0]; //Why can't I print this address
cout << e.c[1]; // Why can't I print this value
}
Run Code Online (Sandbox Code Playgroud)
O/P:0x7fff5451ab68 0x7fff5451ab68
我最近发现了vreinterpret {q} _dsttype_srctype转换运算符.但是,这似乎不支持此链接(页面底部)中描述的数据类型的转换:
一些内在函数使用以下形式的向量类型数组:
<type><size>x<number of lanes>x<length of array>_t这些类型被视为包含名为val的单个元素的普通C结构.
示例结构定义是:
Run Code Online (Sandbox Code Playgroud)struct int16x4x2_t { int16x4_t val[2]; };
你知道如何转换uint8x16_t成uint8x8x2_t?
请注意,使用union无法可靠地解决问题(从非活动成员读取导致未定义的行为编辑:这只是C++的情况,而事实证明C允许类型惩罚),也没有使用指针来强制转换(打破严格别名规则).
VS2019,发布,x86.
template <int i> float get() const {
int f = _mm_extract_ps(fmm, i);
return (float const&)f;
}
Run Code Online (Sandbox Code Playgroud)
使用return (float&)f;编译器时使用
extractps m32, ...
movss xmm0, m32
Run Code Online (Sandbox Code Playgroud)
.正确的结果
使用return (float const&)f;编译器时使用
extractps eax, ...
movd xmm0, eax
Run Code Online (Sandbox Code Playgroud)
.错误的结果
T&和T const&首先是T然后是const的主要思想.Const只是程序员的某种协议.你知道你可以解决它.但汇编代码中没有任何const,但是类型为float IS.我认为对于float和float const而言它必须是汇编中的浮点表示(cpu寄存器).我们可以使用中间int reg32,但最终解释必须是float.
而此时它看起来像回归,因为这之前工作正常.并且在这种情况下使用float也绝对是奇怪的,因为我们不应该考虑浮动const和安全性而是浮动的临时变量并且确实值得怀疑.
微软回答:
嗨Truthfinder,感谢自成一体的复制品.碰巧,这种行为实际上是正确的.正如我的同事@Xiang Fan [MSFT]在内部电子邮件中所述:
由[a c-style cast]执行的转换尝试以下序列:(4.1) - const_cast(7.6.1.11),(4.2) - static_cast(7.6.1.9),(4.3) - static_cast后跟const_cast ,(4.4) - reinterpret_cast(7.6.1.10)或(4.5) - reinterpret_cast后跟const_cast,
如果转换可以用上面列出的多种方式解释,则使用列表中首先出现的解释.
所以在你的情况下,(const float&)被转换为static_cast,其效果是"初始化表达式被隐式转换为类型为"cv1 T1"的prvalue.应用临时实现转换并将引用绑定到结果".
但在另一种情况下,(float&)被转换为reinterpret_cast,因为static_cast无效,这与reinterpret_cast(&operand)相同.
您正在观察的实际"错误"是一个强制转换:"将浮点型值"1.0"转换为等效的int-typed值"1"",而另一个强制转换说"将1.0的位表示形式转换为一个浮点数,然后将这些位解释为int".
出于这个原因,我们建议不要使用c风格的演员表.
谢谢!
MS论坛链接:https://developercommunity.visualstudio.com/content/problem/411552/extract-ps-intrinsics-bug.html
有任何想法吗?
PS我真正想要的是什么:
float val …Run Code Online (Sandbox Code Playgroud) 我有一个16位变量data,即:
volatile uint16_t data;
Run Code Online (Sandbox Code Playgroud)
我需要根据外部传感器上两个8位寄存器的内容填充该值.这些通过I2C/TWI访问.
我的TWI例程是async*,并且有签名:
bool twi_read_register(uint8_t sla, uint8_t reg, uint8_t *data, void (*callback)(void));
Run Code Online (Sandbox Code Playgroud)
这读取的价值reg就sla成*data,然后调用callback().
如果我知道它uint16_t被安排在记忆中,比如说MSB LSB,那么我可以这样做:
twi_read_register(SLA, REG_MSB, (uint8_t *)&data, NULL);
twi_read_register(SLA, REG_LSB, (uint8_t *)&data + 1, NULL);
Run Code Online (Sandbox Code Playgroud)
但是,我不喜欢将endian依赖到我的代码中.有没有办法以与endian无关的方式实现这一目标?
(旁注:我目前的实际解决方法是使用结构,即:
typedef struct {
uint8_t msb;
uint8_t lsb;
} SensorReading;
Run Code Online (Sandbox Code Playgroud)
但我很好奇,如果我能用一个简单的方法做到这一点uint16_t)
编辑
(*async我的意思是分裂阶段,*data即将在未来的某个时间点设置,此时callback如果请求,将通过函数通知被调用者)
在这个答案的评论中,据说使用如下的联合将整数分割成它们的字节将是未定义的行为.在那个地方给出的代码是相似的,虽然与此不相同,请注意我是否更改了代码的未定义行为相关方面.
union addr {
uint8_t addr8[4];
uint32_t addr32;
};
Run Code Online (Sandbox Code Playgroud)
到目前为止,我认为这将是一个很好的做法,addr = {127, 0, 0, 1};并得到相应 uint32_t的回报.(我承认根据我的系统的字节顺序,这可能产生不同的结果.但问题仍然存在.)
这是未定义的行为吗?如果是这样,为什么?(我不知道C++中的UB是什么意思是访问非活动的联盟成员.)
C99
C++ 03
然而
结论
uint8_t[4]和uint32_t不是同一类型(我猜,一个严格的混叠的东西)(加上两个都不是POD结构/联合)上面确实是UB?C++ 11
c++ ×8
c ×6
embedded ×2
arm ×1
assembly ×1
casting ×1
endianness ×1
intrinsics ×1
logarithm ×1
math ×1
neon ×1
sqrt ×1
sse ×1
type-punning ×1
unions ×1
visual-c++ ×1