Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何将具有两个无符号短字符的结构视为无符号int?(C)中_C_Struct_Fixed Point - Fatal编程技术网

如何将具有两个无符号短字符的结构视为无符号int?(C)中

如何将具有两个无符号短字符的结构视为无符号int?(C)中,c,struct,fixed-point,C,Struct,Fixed Point,我创建了一个表示定点正数的结构。我希望小数点两侧的数字由2个字节组成 typedef struct Fixed_t { unsigned short floor; //left side of the decimal point unsigned short fraction; //right side of the decimal point } Fixed; 现在我想添加两个固定点数,fixed x和fixed y。为此,我将它们视为整数并相加 (Fixed) ( (int

我创建了一个表示定点正数的结构。我希望小数点两侧的数字由2个字节组成

typedef struct Fixed_t {
    unsigned short floor; //left side of the decimal point
    unsigned short fraction; //right side of the decimal point
} Fixed;
现在我想添加两个固定点数,
fixed x
fixed y
。为此,我将它们视为整数并相加

(Fixed) ( (int)x + (int)y );
但正如我的VisualStudio2010编译器所说,我无法在
Fixed
int
之间进行转换

正确的方法是什么


编辑:我不致力于固定的
{short floor,short fraction}
实现

这在可移植性上是不可能的,因为编译器不能保证固定的
将使用与
int
相同的空间量。正确的方法是定义一个函数
Fixed add(Fixed a,Fixed b)

如果必须,您可以使用union,但要注意endian问题。你可能会发现这个算法不起作用,而且肯定是不可移植的

typedef struct Fixed_t {
   union { 
        struct { unsigned short floor; unsigned short fraction }; 
        unsigned int whole;
         };
} Fixed;
(我认为)哪一种更可能在big-endian中工作(Windows/Intel不是)。

尝试以下方法:

typedef union {
    struct Fixed_t {
        unsigned short floor; //left side of the decimal point
        unsigned short fraction; //right side of the decimal point
    } Fixed;
    int Fixed_int;
}

只需分别添加这些片段。你需要知道表示“1”的分数的值-这里我称之为
FRAC_MAX

 // c = a + b
 void fixed_add( Fixed* a, Fixed* b, Fixed* c){
     unsigned short carry = 0;
     if((int)(a->floor) + (int)(b->floor) > FRAC_MAX){
         carry = 1;
         c->fraction = a->floor + b->floor - FRAC_MAX; 
     }
     c->floor = a->floor + b->floor + carry;
 }
或者,如果只是将固定点设置为2字节边界,则可以执行以下操作:

void fixed_add( Fixed* a, Fixed *b, Fixed *c){
    int ia = a->floor << 16 + a->fraction;
    int ib = b->floor << 16 + b->fraction;
    int ic = ia + ib;
    c->floor = ic >> 16;
    c->fraction = ic - c->floor;
}
void fixed\u add(固定*a、固定*b、固定*c){
int ia=a->地板分数;
int ib=b->地板分数;
int ic=ia+ib;
c->floor=ic>>16;
c->分数=ic-c->地板;
}

如果您的编译器将两个短字符放在4字节上,那么您可以使用memcpy在结构中复制int,但正如另一个答案中所述,这是不可移植的。。。而且相当难看

你真的在乎用一个单独的方法分别添加每个字段吗?
出于性能原因,是否要保留整数?

您可以尝试一次恶意攻击,但endian ness存在一个问题。无论您如何转换,编译器如何知道您希望
floor
是结果中最重要的部分,而
fraction
是不太重要的部分?任何依赖于重新解释记忆的解决方案都将适用于一个端点,而不是另一个端点

你应该:

(1) 明确定义转换。假设
short
为16位:

unsigned int val = (x.floor << 16) + x.fraction;

这将适用于big-endian系统,其中Fixed没有填充(整数类型没有填充位)。在一个小的endian系统中,你需要固定的成员处于另一个顺序,这就是为什么它是令人讨厌的。有时,通过memcpy进行转换是正确的做法(在这种情况下,这是一个“技巧”,而不是一个“讨厌的黑客”)。这可不是那种情况。

您可以使用以下命令将任何可寻址类型转换为另一种类型:

// add two Fixed 
Fixed operator+( Fixed a, Fixed b ) 
{   
...
}

//add Fixed and int
Fixed operator+( Fixed a, int b ) 
{   
...
}
*(newtype *)&var
一些魔法:

typedef union Fixed {
    uint16_t w[2];
    uint32_t d;
} Fixed;
#define Floor w[((Fixed){1}).d==1]
#define Fraction w[((Fixed){1}).d!=1]
要点:

  • 我使用固定大小的整数类型,因此您不需要依赖
    short
    为16位和
    int
    为32位
  • Floor
    Fraction
    的宏(大写以避免与
    Floor()
    函数冲突)以endian独立的方式访问这两个部分,如
    foo.Floor
    foo.Fraction
编辑:应OP的要求,宏的说明:

联合是一种声明由若干不同重叠类型组成的对象的方法。这里我们有
uint16\u t w[2]重叠
uint32\u t d,可以访问2个16位单位或1个32位单位的值

(Fixed){1}
是一个复合文本,可以更详细地写成
(Fixed){1,0}
。它的第一个元素(
uint16_t w[2];
)用
{1,0}
初始化。表达式
((固定){1}).d
然后计算为32位整数,其前16位的一半为1,后16位的一半为0。在小端系统上,这个值是1,因此
((固定){1}).d==1
计算为1(真)和
((固定){1}).d=1的计算结果为0(false)。在大端系统上,情况正好相反

因此,在一个小端点系统上,
Floor
w[1]
Fraction
w[0]
。在大端系统上,
Floor
w[0]
Fraction
w[1]
。无论哪种方式,最终都会存储/访问平台endian ness的32位值的正确一半


理论上,一个假设的系统可以对16位和32位的值使用完全不同的表示(例如,将两部分的位交错),从而破坏这些宏。实际上,这是不会发生的。:-)

我同意。但我实际上是在问add函数的实现。我希望固定加法函数与int加法一样快。这就是我决定将定点数转换为整数进行加法的原因。
\uuuuu attribute\uuuuuuu((\ uuuu packed\uuuuuu))
应该添加到struct,这样编译器就不会试图优化字节对齐。@Till:谢谢。我应该在结构的什么地方添加属性uuu(uuu packed))东西?@snakile
struct{unsigned short floor;unsigned short fraction}属性uuu(uuu packed_u))您不应该使用
\uuuuuu属性((\uuuu packed\uuuuu))
。这段代码在任何实际的ABI上都能很好地工作,没有非标准的打包选项。@R。。难道没有编译器在4字节边界上对齐结构成员吗?可能是在打开优化时?最好使用int来存储您的fixed(可能是typedef'd)并使用移位和按位操作来提取值的整数和小数部分。这并不完全符合标准,但比将struct转换为int更具可移植性。@Vova:谢谢,这就是我最终所做的。实际上你不能。根据别名规则,这是明确未定义的行为。这是未定义的行为,但
typedef union Fixed {
    uint16_t w[2];
    uint32_t d;
} Fixed;
#define Floor w[((Fixed){1}).d==1]
#define Fraction w[((Fixed){1}).d!=1]