C++ 演员和工会一样安全吗?

C++ 演员和工会一样安全吗?,c++,c,arduino,embedded,unions,C++,C,Arduino,Embedded,Unions,我想把像float这样的大变量拆分成字节段,然后通过UART逐字节串行发送这些变量。我正在使用C/C++ 一种方法是将我要发送给工会的值深度复制,然后发送。我认为这将是100%安全,但速度缓慢。工会将是这样的: union mySendUnion { mySendType sendVal; char[sizeof(mySendType)] sendArray; } sendType myValue = 443.2;

我想把像float这样的大变量拆分成字节段,然后通过UART逐字节串行发送这些变量。我正在使用C/C++

一种方法是将我要发送给工会的值深度复制,然后发送。我认为这将是100%安全,但速度缓慢。工会将是这样的:

   union mySendUnion
   {
       mySendType sendVal;
       char[sizeof(mySendType)] sendArray; 
    }
            sendType myValue = 443.2;

    char* sendChar = (char*)myValue; 

    for(char i=0; i< sizeof(sendType) ; i++)
    {
        Serial.write(*(sendChar+j), 1);
    }
另一个选项是将指向我要发送的值的指针转换为指向特定联合的指针。这还安全吗

第三个选项可以是将指针强制转换为要发送给char的值,然后像这样递增指针:

   union mySendUnion
   {
       mySendType sendVal;
       char[sizeof(mySendType)] sendArray; 
    }
            sendType myValue = 443.2;

    char* sendChar = (char*)myValue; 

    for(char i=0; i< sizeof(sendType) ; i++)
    {
        Serial.write(*(sendChar+j), 1);
    }
我已经成功地使用了上述指针算法,但我不确定它在所有情况下是否安全。我关心的是,如果我们使用一个32位处理器,并且想要发送一个浮点。编译器选择将此32位浮点存储到一个内存单元中,但只将一个字符存储到每个32位单元中

然后,每个计数器增量将使程序指针增加一个完整的内存单元,我们将错过浮点


C标准中是否有什么东西阻止了这种情况,或者这可能是某个编译器的问题

在字节流上发送浮点数据时,一般的建议是使用一些技术,以确保数据格式定义良好,最好是与体系结构无关,注意问题

您可以使用-或者-这是一种二进制格式,有关详细信息,请参阅。对于C++,也请参阅

除非速度或数据大小非常关键,否则我建议改为使用文本格式,比如文本格式,可能更详细,但更易于调试和记录。有几个很好的库支持它,例如C++或C.</P> 请注意,串行端口的速度非常慢。因此,序列化处理时间可以忽略不计


无论您做什么,请记录序列化格式,即使对于内部项目也是如此。

在字节流上发送浮点数据时,一般的建议是使用一些技术,以确保数据格式定义良好,最好是与体系结构无关的,当心问题

您可以使用-或者-这是一种二进制格式,有关详细信息,请参阅。对于C++,也请参阅

除非速度或数据大小非常关键,否则我建议改为使用文本格式,比如文本格式,可能更详细,但更易于调试和记录。有几个很好的库支持它,例如C++或C.</P> 请注意,串行端口的速度非常慢。因此,序列化处理时间可以忽略不计

无论您做什么,请记录序列化格式,即使对于内部项目也是如此。

对[[un]signed]char[const]*的转换是合法的,并且在读取时不会引起问题,因此这是一个很好的选项,即在修复char*sendChar=reinterpret_cast&myValue;,既然你在做这件事,就让它保持不变

现在另一个问题来了,当你阅读的时候,因为你不能安全地使用同样的方法来阅读。一般来说,复制变量的成本远低于通过UART发送变量的成本,因此我在读取序列时只使用union。

对[[un]signed]char[const]*的强制转换是合法的,并且在读取时不会引起问题,因此这是一个很好的选择,即在修复char*sendChar=reinterpret\u cast&myValue;,既然你在做这件事,就让它保持不变


现在另一个问题来了,当你阅读的时候,因为你不能安全地使用同样的方法来阅读。一般来说,复制变量的成本远低于通过UART发送的成本,因此我在读取串行数据时只使用union。

首先,您不能用C/C++编写代码。没有C/C++这样的语言,因为它们是根本不同的语言。因此,关于工会的答案大相径庭

关于标题:

演员和工会一样安全吗

不,通常不会,因为天气不好。也就是说,如果用指向不兼容类型的指针键入某个特定类型的指针,将导致未定义的行为。此规则的唯一例外是,当您通过指向有符号或无符号字符的指针对对象进行别名化来读取或操作对象的字节表示形式时。就像你的情况一样

然而,工会是完全不同的杂种。在C99和以后,允许通过复制和从联合读取的类型双关,但是导致C89和C++的所有版本中的未定义行为。 在一个方向上,您还可以安全地在C99中键入pun,然后使用指向union的指针键入pun,如果您将原始union作为实际对象的话。像这样:

union p {
    char c[sizeof(float)];
    float f;
} pun;
union p *punPtr = &pun;

punPtr->f = 3.14;
send_bytes(punPtr->c, sizeof(float));
因为指向一个联合体的指针指向它的所有成员,反之亦然,C99,我不记得确切的参数,大约是6.2.5,IIRC。但从另一个角度看,情况并非如此:

总而言之:以下代码段在C89、C99、C11和C++中都有效:

float f = 3.14;
char *p = (char *)&f;
size_t i;
for (i = 0; i < sizeof f; i++) {
    send_byte(p[i]); // hypotetical function
}

但是,以下内容无效:

float f = 3.14;
unsigned *u = (unsigned *)&f;
printf("%u\n", *u); // undefined behavior triggered!

另一个始终保证有效的解决方案是memcpy。memcpy函数在两个对象之间执行字节复制。不要让我觉得它很慢——在大多数现代编译器和stdlib实现中,它是一个固有的函数。

首先,您不能用C/C++编写代码。没有C/C++这样的语言,因为它们是根本不同的语言。因此,关于工会的答案大相径庭

关于标题:

演员和工会一样安全吗

不,通常不会,因为天气不好。也就是说,如果用指向不兼容类型的指针键入某个特定类型的指针,将导致未定义的行为。此规则的唯一例外是,当您通过指向有符号或无符号字符的指针对对象进行别名化来读取或操作对象的字节表示形式时。就像你的情况一样

然而,工会是完全不同的杂种。在C99和以后,允许通过复制和从联合读取的类型双关,但是导致C89和C++的所有版本中的未定义行为。 在一个方向上,您还可以安全地在C99中键入pun,然后使用指向union的指针键入pun,如果您将原始union作为实际对象的话。像这样:

union p {
    char c[sizeof(float)];
    float f;
} pun;
union p *punPtr = &pun;

punPtr->f = 3.14;
send_bytes(punPtr->c, sizeof(float));
因为指向一个联合体的指针指向它的所有成员,反之亦然,C99,我不记得确切的参数,大约是6.2.5,IIRC。但从另一个角度看,情况并非如此:

总而言之:以下代码段在C89、C99、C11和C++中都有效:

float f = 3.14;
char *p = (char *)&f;
size_t i;
for (i = 0; i < sizeof f; i++) {
    send_byte(p[i]); // hypotetical function
}
但是,以下内容无效:

float f = 3.14;
unsigned *u = (unsigned *)&f;
printf("%u\n", *u); // undefined behavior triggered!


另一个始终保证有效的解决方案是memcpy。memcpy函数在两个对象之间执行字节复制。不要让我开始慢,在大多数现代编译器和STDLIB实现中,它是一个内在的函数。使用/TP>使用类型双关的联合会导致C++中的未定义行为,并且不应该被认为是安全的。他们只是碰巧经常工作,大部分时间人们都在这样做…typcast比较安全,因为它没有对齐问题。你认为工会为什么会慢?一定要考虑到endianness;并非所有平台都以相同的顺序存储组成一个浮点的四个字节,例如32位浮点,因此您需要确保连接的两端在表示法上一致。@dwelch您所说的类型转换是什么意思,因为它没有对齐问题?两种解决方案在C++中都是错误的,如果类型不同或者两者在C99和以后都是好的,当类型兼容或引用类型的混叠指针是[un]符号char或者只有基于联合的解决方案在C中是好的时,当类型不同但双击指针不是char *或者只有指针的解决方案在C++中是好的,当类型不兼容时,引用类型的混叠指针是[un]符号char。使用类型绑定的联合将导致C++中的未定义行为,并且不应该被认为是安全的。两者都会失败。他们只是碰巧经常工作,大部分时间人们都在这样做…typcast比较安全,因为它没有对齐问题。你认为工会为什么会慢?一定要考虑到endianness;并非所有平台都以相同的顺序存储组成一个浮点的四个字节,例如32位浮点,因此您需要确保连接的两端在表示法上一致。@dwelch您所说的类型转换是什么意思,因为它没有对齐问题?两种解决方案在C++中都是错误的,如果类型不同或者两者在C99和以后都是好的,当类型兼容或引用类型的混叠指针是[un]符号char或者只有基于联合的解决方案在C中是好的时,当类型不同但双击指针不是char *或者只有指针的解决方案在C++中是好的,当类型不兼容时,引用类型的混叠指针是[un]符号char。在C99和以后,可以允许通过拷贝到类型支持双关惩罚,并且允许在C99和以后读取,但会导致未定义的行为。[C89和]所有版本的C++.@ DavIDRODR Guez Doubas都很抱歉,我不理解,支持如何?我觉得它在C++中是合法的,但是你声称它不是。你有一个支持该语句的引用吗?这是一个灰色的区域,但是很明显,类型双关是由我所知道的所有C++编译器支持的,甚至是推荐的。在gcc手册页中,这是一种很好的方法。@DavidRodríguez dribeas啊,我明白了。我现在正在搜索C++11标准。@DavidRodríguez dribeas我们来看看,例如,C++11,9.2:如果一个标准布局联合包含两个或多个共享一个初始序列的标准布局结构,并且如果标准布局联合对象当前为如果是这些标准布局结构之一,则允许检查公共ini
它们中任何一个的一部分然后,在9.5中:在联合中,在任何时候最多一个非静态数据成员可以处于活动状态,也就是说,在任何时候,最多一个非静态数据成员的值可以存储在联合中。下面是关于标准的部分……在C99和以后,您可以通过复制和支持来支持类型双关吗?但是在C89 +的所有版本中都会导致未定义的行为。?@ DavIDRODR?Guez DunBeas抱歉,我不理解,支持如何?我觉得它在C++中是合法的,但你声称不是。您是否有支持该声明的报价?这是一个灰色的区域,但很明显的是,类型双关是由我所知道的所有C++编译器支持的,甚至是GCC手册中的推荐方法。我现在正在搜索C++11标准。@DavidRodríguez dribeas我们开始了,例如,C++11,9.2:如果一个标准布局联合体包含两个或多个共享一个共同初始序列的标准布局结构,并且如果标准布局联合体对象当前包含其中一个标准布局结构,允许检查其中任何一个的公共首字母部分。-然后,在9.5中:在联合中,在任何时候最多一个非静态数据成员可以处于活动状态,也就是说,在任何时候,最多一个非静态数据成员的值可以存储在联合中。下面是上面关于标准的部分。。。