Typedef将测量单位放在C中

时间:2015-01-19 09:12:36

标签: c data-structures typedef

使用 typedef 将测量单位放入名称是否是一种好习惯? (并重命名标准类型)像这样:

typedef int16_t  MilliAmp_t;        /* 1 mA */

3 个答案:

答案 0 :(得分:4)

您只是重命名某些类型。它不会在编译器中带来任何额外的检查(除非该编译器是专门定制的;如果使用GCC,你可以考虑通过MELT进行自定义,但这种定制不是一项微不足道的任务),在某种意义上以下代码

 MilliAmp_t x=0,y=1,z=2;
 x = y * z;

总是在没有警告的情况下编译(在C中),即使物理上乘以两个电流并将结果放在某个当前变量中也没有任何意义。

但是,你的typedef有一个小的文档值:如果你声明一个像

这样的原型
MilliWatt_t electical_power (MilliAmp_t current, MilliVolt_t tension);

然后一些读者可能会觉得有帮助(但也许不是我)。

答案 1 :(得分:3)

是的,这种typedef很常见。虽然C不提供强类型,这会阻止您将当前数量分配给电压变量,但这样的做法确实可以让您一目了然地看到变量的含义,而不将该信息编码到名称中。

当我亲自为小型微控制器编写物理分析代码时,我更愿意选择范围而不仅仅是“1步= 1毫安”,以便最大限度地提高精度。所以,我更喜欢voltage_tcurrent_t,然后在将它们与已知物理量相关联时使用全局转换系数。

使用整数进行物理数学运算时,溢出和精度损失是重要的考虑因素。将变量保持在适当的物理单位中往往有助于将中间结果保持在适当的动态范围内,从而避免这些问题,只要物理系统将其电压和电流保持在您为统一计算用途选择的范围内。

如果你拥有 FPU,我建议使用它,不要打扰SI前缀,因为它可以透明地处理毫米,微米和其他任何东西而不会弄乱系数。使用typedef double amps;仍然有助于以合理和说明的方式编码方程式,您可以在以后轻松调整整个程序的精度。无论如何,这样做。

答案 2 :(得分:1)

正如其他人所指出的,typedef没有定义新类型,它引入了别名。

如果您真的想要这种安全级别,那么您可以在struct

中装箱值
typedef struct {
    int16_t v;

} MillAmp_t ;

它获得了打字开销:

#include <stdint.h>
#include <stdio.h>

typedef struct {
    int16_t v;

} MilliAmp_t ;

typedef struct {
    int16_t v;

} MilliOhms_t ;

typedef struct {
    int16_t v;

} MilliWatt_t ;


MilliWatt_t power_loss(MilliAmp_t current,MilliOhms_t resistance){
    //NB: Using int16_t makes this seriously under/overflow prone.
    //So we upsize everything for the best shot at a result.
    int64_t currentl=current.v;
    int64_t resistancel=resistance.v;
    int64_t result=currentl*currentl*resistancel/1000000L;
    return (MilliWatt_t){result};
}    

int main(void) {
    MilliAmp_t current={1000};
    MilliOhms_t resistance={2000};

    MilliWatt_t power=power_loss(current,resistance);

    printf("%d\n",(int)power.v);

    //MilliWatt_t rewop=power_loss(resistance,current);//Compiler Error! Hurray!!

    return 0;
}

但开销并不大。你可以把它包装成一个marco:

#define VALUE(S)((S).v)

但我不相信这有帮助。

不要被告诉您不需要此解决方案的人自动说服。如果你的计算非常复杂,涉及许多不同的单位,你可以为这个适度的开销节省很多心痛。

然而,通常的惯例是将单位“变形”为名称:

int16_ power_loss_MilliWatts(int16_t current_MilliAmps,int16_t resistance_MilliOhms);

这往往会有所帮助,因为程序员倾向于按名称引用参数并识别该后缀的意图。但显然编译器没有提供疏忽。

在你问之前,这个'装箱'不太可能在任何真实的编译器上有任何内存或速度上的开销(当然在没有调试的情况下进行编译)。

PS:任何拒绝接受这个甚至可能有价值的人(在相关情况下)都可能会对一些经典的单位转换吵架感到好笑。

http://mentalfloss.com/article/25845/quick-6-six-unit-conversion-disasters

还有哈勃太空望远镜和许多其他翘首。 我已经看到很多(大量)单元测试错误出现了100倍,因为人们使用术语百分比和因子松散且可互换。