C 将16位值转换为8位值的有效方法

C 将16位值转换为8位值的有效方法,c,bit-manipulation,C,Bit Manipulation,我有一个保存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

我有一个保存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);
}
我想知道,从16位变量中获取8 LSB是一种好方法吗

编辑:
请使用这种特殊的实现方式添加性能问题(从内存和速度的角度)

您可以执行以下操作:

uint16_t val = 0xABCD;
uint8_t vr = val & 0x00FF;    // Bitwise AND Operation

使用此按位操作,您将获得8位的
LSB

您可以使用位屏蔽概念。
这样地,


或者,这也可以通过简单的显式类型转换来实现,因为8位整数仅从16位值中携带LBS 8位,并丢弃剩余的MSB 8位(默认情况下,当分配更大的值时)。

虽然两个答案都正确,但此处的位屏蔽是完全冗余的。当转换为
uint8\u t
时,它会隐式发生。如果没有精确大小的整数类型(并且,说到性能,你应该考虑这一点,因为在使用机器的本机字大小时性能一般最好),这将是不同的:

unsigned int val = 0xabcd;
unsigned int vr = val & 0xff;
assert(vr == 0xcd);
但是当你真的需要这些精确大小的类型时,最好的代码是IMHO

uint16_t val = 0xabcd;
uint8_t vr = (uint8_t) val;
明确的演员阵容是在这里记录的意图!如果没有它,一个好的编译器将警告您隐式转换可能会丢失信息(并且您应该始终启用编译器警告,例如,对于gcc
-Wall-Wextra-pedantic
,以捕获您意外进行此类转换的情况)

使用大小完全相同的类型的所有变体的性能应该是相同的,因为一个好的编译器将为它们发出相同的代码。使用unsigned int的版本可能会更好一些


[编辑]:当您询问内存性能时:您不太可能通过使用
uint8\t
获得一些东西,因为某些体系结构要求小于本机字长的值与字边界对齐。如果它们不需要,对齐它们可能会更快,因此编译器可能会决定这样做。这只会引入未使用的填充字节。有了gcc,您可以使用选项
-Os
来优化大小,并且由于
x86
体系结构是字节可寻址的,这可能会导致在PC上使用
uint8\t
而无需填充,但因此速度较低。大多数情况下,速度和内存是一种折衷,你可以选择其中之一。

虽然上面的答案是正确的,但这里有另一种方法。此方法不需要按位操作

#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{
结构{
uint8_t lsb;
uint8_t msb;
}生的;
uint16_t数据;
}我的号码;
int main(int argc,char*argv[]){
mynumber.data=0xFEAB;
printf(“msb=%u,lsb=%u\n”,mynumber.raw.msb,mynumber.raw.lsb);
返回1;
}

从性能(内存和速度)的角度来看,它与“vr=val”有什么不同?@Amol:那不是真的。对于无符号类型,在OP使用时,其行为由标准指定。@caf:通常直接将16位变量直接赋值到8位变量是不好的编程实践,我将检查有关其原因的更多信息。我完全同意你的观点,因为它是
无符号的
@saurabhagarwal:你的问题是关于无符号类型的。有符号类型是另一种野兽。你也可以使用
vr=(uint8_t)val
(这正是OP所做的,只是缺少显式强制转换(在最坏的情况下会产生编译警告,但在任何情况下都不会产生任何运行时影响))。删除我的答案,我忽略了变量是无符号的。因此,对于无符号类型。它将依赖于平台,而对于有符号类型,则不会。对于无符号类型,行为(在您的问题代码中)定义得很好。对于带符号的类型,由于符号位的原因,答案会变得更加棘手。不需要强制转换。无论如何,不需要强制转换,因为按位和赋值是指定的行为。@alk,是的,您是对的。但是理解它是一种很好的编程实践。我在回答中也用了“默认”一词来纠正这一点。
uint16_t val = 0xabcd;
uint8_t vr = (uint8_t) val;
#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;
}