算术运算混合char和double的潜在问题?

时间:2012-03-07 11:56:55

标签: c

我对C非常陌生,我正在编写Ruby C扩展。其中一个函数应该计算两种颜色之间的平淡。 Color结构使用char来存储RGB值。混合比率为double,介于0.0和1.0之间。

在我在这里完成的操作中混合chardouble是不好的做法?可能会有潜在的问题吗?

我猜测如果重量不在0.0和1.0之间,可能会出现问题,因为它可能导致小于0或大于255的值。

我应该明确地投射类型吗?

typedef struct Color    Color;

static struct Color {
  unsigned char red, green, blue, alpha;
};


static Color
color_blend(  Color color1, Color color2, double weight )
{
  Color color3 = { 0, 0, 0, 0 };

  color3.red    = ( 1 - weight ) * color1.red   + ( weight * color2.red );
  color3.green  = ( 1 - weight ) * color1.green + ( weight * color2.green );
  color3.blue   = ( 1 - weight ) * color1.blue  + ( weight * color2.blue );
  color3.alpha  = ( 1 - weight ) * color1.alpha + ( weight * color2.alpha );

  return color3;
}

4 个答案:

答案 0 :(得分:3)

您没有需要来执行显式投射;编译器的隐式转换应该做同样的事情。但是,考虑显式演员表有两个很好的理由:

  1. 在较高警告级别上,您可能会收到有关隐式强制转换的精度损失等警告消息。
  2. 明确的演员表有助于向您的代码读者记录您的意图。
  3. 我认为您的代码不存在任何范围问题。但是,您可以考虑添加舍入到最近的行为,因为当前的计算值是99.999将截断为99。

答案 1 :(得分:1)

在您的特定示例中,只要您以后不更改表达式,它就可以正常工作。你的代码中有很多隐式的促销活动,所以很容易在某个地方搞错误。

让我们剖析这一行:

color3.red    = ( 1 - weight ) * color1.red   + ( weight * color2.red );

如果我们只看一下使用的类型,这个表达式相当于:

unsigned char = (signed int - double) * unsigned char + (double * unsigned char);

让我们假设编译器使用从左到右的评估顺序。然后将以下列方式计算该表达式:

unsigned char = (signed int - double) * unsigned char + (double * unsigned char);  //balance ->
unsigned char = (double - double) * unsigned char + (double * unsigned char); //calculate->
unsigned char = double * unsigned char + (double * unsigned char); //balance->
unsigned char = double * double + (double * unsigned char); //calculate->
unsigned char = double + (double * unsigned char); //balance->
unsigned char = double + (double * double); //calculate->
unsigned char = double + double; // calculate->
unsigned char = double; // truncate->
unsigned char = unsigned char;

如果任何子表达式不包含double类型,则可能会发生错误。如果您不了解所有隐式类型转换,则修改此表达式将非常危险。如果您不确定它们,请使用显式类型转换。

像MISRA-C这样的编码标准完全禁止隐含转换,因为这种转换有时是危险且不可预测的。符合MISRA-C标准的代码版本如下:

color3.red    = (double) ((1.0-weight) * color1.red) + 
                (double) (weight * color2.red);

(由于您使用的是unsigned char,而不是普通的char,您正在摆脱许多问题。如果您使用char,那么所有投注都将被取消。)

答案 2 :(得分:0)

为了确保安全,我认为你应该采取下一步措施

unsigned char source_color = 230;
double coef = 0.7;
double res = source_color * coef; //is OK as char will be converted 
//to double before operation

if(res < 0)
     res = 0;
if(res > 255)
     res = 255;
//this is needet to prevent from such bug. 
//If you wan't to convert for example double(256) to char you will have char(1) 
//as it will be counted 256 % 255 as 255 is max char can fit

unsigned char result_color = (unsigned char)res; //This will trucate fraction 
//part of the number for example 1.2 => 1 or 1.999 => 1. 
//If you want to have 1.999 => 2 you should round you double number.

此解决方案是安全的。

答案 3 :(得分:-1)

如果你不在常规算术中使用显式强制转换,那会更好。编译器知道如何进行优化,如果你开始告诉它使用哪种类型,你可能会无意中排除某些选项并减慢你的代码。

但要注意,如果你有这样的东西:

double_var = int_var1 / int_var2;

它将执行整数除法,然后将结果转换为double,因此您将获得舍入错误。只要其中一个变量是浮点类型(就像你有的那样)它应该可以正常工作。

与常量相同:如果你想要浮点数学,请使用0.0而不是普通0