将 16 位值转换为 8 位值的有效方法
efficient way to convert 16 bit value to 8 bit value
我有一个包含 16 位值的变量。我只需要 8 LSB。其余 8 位需要丢弃。
我正在使用此代码来执行此操作。
#include<stdio.h>
#include<stdint.h>
int main(int argc, char *argv[])
{
int linkIndx,size=128;
uint16_t val = 0xABCD;
uint8_t vr;
vr = val; //this assignment discards upper 8-bits
printf("0x%X 0x%X ", val, vr);
}
结果:
0xABCD 0xCD
我想知道,从 16 位变量中取出 8 LSB 是一种好方法吗?
编辑:
请使用这种特定的实现方式添加性能问题(从内存和速度的角度来看)。
您可以进行以下操作:
uint16_t val = 0xABCD;
uint8_t vr = val & 0x00FF; // Bitwise AND Operation
使用这个按位运算你会得到 8 位 LSB
您可以使用位掩码概念。
像这样,
uint16_t val = 0xABCD;
uint8_t vr = (uint8_t) (val & 0x00FF);
或者这也可以通过简单的显式类型转换来完成,因为 8 位整数仅携带 16 位值中的 LBS 8 位,并丢弃剩余的 MSB 8 位(默认情况下,当分配一个较大的值)。
虽然两个答案都是正确的,但这里的位掩码是完全多余的。它在转换为 uint8_t
时隐式发生。如果没有精确大小的整数类型(而且,说到性能,您应该考虑这一点,因为使用机器的本机字大时通常性能最好),这将有所不同:
unsigned int val = 0xabcd;
unsigned int vr = val & 0xff;
assert(vr == 0xcd);
但是当你真的需要这些精确大小的字体时,最好的代码是恕我直言
uint16_t val = 0xabcd;
uint8_t vr = (uint8_t) val;
显式转换是为了记录意图!没有它,一个好的编译器会警告您隐式转换可能会丢失信息(并且您应该始终启用编译器警告,例如 gcc -Wall -Wextra -pedantic
,以捕获意外进行此类转换的情况 ).
使用大小完全相同的类型的所有变体的性能应该是相同的,因为一个体面的编译器会为所有这些变体发出相同的代码。仅使用 unsigned int
的版本可能 表现更好一些。
[编辑]:正如您询问 内存性能 一样:您不太可能通过使用 uint8_t
因为某些体系结构需要小于本机字大小的值才能与字边界对齐。如果他们不需要它,让它们对齐可能仍然更快,因此编译器可能会决定这样做。这只是引入了未使用的填充字节。使用 gcc,您可以使用选项 -Os
来优化大小,并且由于 x86
体系结构是字节可寻址的,这可能导致 uint8_t
在 PC 上使用时没有填充,但因此较低的速度。大多数时候,速度与内存是一种权衡,你可以选择其中之一。
虽然上面的答案是正确的,但这里有另一种方法。此方法不需要按位运算
#include <stdint.h>
#include <stdio.h>
union converted16{
struct{
uint8_t lsb;
uint8_t msb;
}raw;
uint16_t data;
}mynumber;
int main(int argc, char *argv[]){
mynumber.data = 0xFEAB;
printf("msb = %u, lsb = %u\n",mynumber.raw.msb, mynumber.raw.lsb);
return 1;
}
我有一个包含 16 位值的变量。我只需要 8 LSB。其余 8 位需要丢弃。
我正在使用此代码来执行此操作。
#include<stdio.h>
#include<stdint.h>
int main(int argc, char *argv[])
{
int linkIndx,size=128;
uint16_t val = 0xABCD;
uint8_t vr;
vr = val; //this assignment discards upper 8-bits
printf("0x%X 0x%X ", val, vr);
}
结果:
0xABCD 0xCD
我想知道,从 16 位变量中取出 8 LSB 是一种好方法吗?
编辑:
请使用这种特定的实现方式添加性能问题(从内存和速度的角度来看)。
您可以进行以下操作:
uint16_t val = 0xABCD;
uint8_t vr = val & 0x00FF; // Bitwise AND Operation
使用这个按位运算你会得到 8 位 LSB
您可以使用位掩码概念。
像这样,
uint16_t val = 0xABCD;
uint8_t vr = (uint8_t) (val & 0x00FF);
或者这也可以通过简单的显式类型转换来完成,因为 8 位整数仅携带 16 位值中的 LBS 8 位,并丢弃剩余的 MSB 8 位(默认情况下,当分配一个较大的值)。
虽然两个答案都是正确的,但这里的位掩码是完全多余的。它在转换为 uint8_t
时隐式发生。如果没有精确大小的整数类型(而且,说到性能,您应该考虑这一点,因为使用机器的本机字大时通常性能最好),这将有所不同:
unsigned int val = 0xabcd;
unsigned int vr = val & 0xff;
assert(vr == 0xcd);
但是当你真的需要这些精确大小的字体时,最好的代码是恕我直言
uint16_t val = 0xabcd;
uint8_t vr = (uint8_t) val;
显式转换是为了记录意图!没有它,一个好的编译器会警告您隐式转换可能会丢失信息(并且您应该始终启用编译器警告,例如 gcc -Wall -Wextra -pedantic
,以捕获意外进行此类转换的情况 ).
使用大小完全相同的类型的所有变体的性能应该是相同的,因为一个体面的编译器会为所有这些变体发出相同的代码。仅使用 unsigned int
的版本可能 表现更好一些。
[编辑]:正如您询问 内存性能 一样:您不太可能通过使用 uint8_t
因为某些体系结构需要小于本机字大小的值才能与字边界对齐。如果他们不需要它,让它们对齐可能仍然更快,因此编译器可能会决定这样做。这只是引入了未使用的填充字节。使用 gcc,您可以使用选项 -Os
来优化大小,并且由于 x86
体系结构是字节可寻址的,这可能导致 uint8_t
在 PC 上使用时没有填充,但因此较低的速度。大多数时候,速度与内存是一种权衡,你可以选择其中之一。
虽然上面的答案是正确的,但这里有另一种方法。此方法不需要按位运算
#include <stdint.h>
#include <stdio.h>
union converted16{
struct{
uint8_t lsb;
uint8_t msb;
}raw;
uint16_t data;
}mynumber;
int main(int argc, char *argv[]){
mynumber.data = 0xFEAB;
printf("msb = %u, lsb = %u\n",mynumber.raw.msb, mynumber.raw.lsb);
return 1;
}