我对C非常陌生,我正在编写Ruby C扩展。其中一个函数应该计算两种颜色之间的平淡。 Color
结构使用char
来存储RGB值。混合比率为double
,介于0.0和1.0之间。
在我在这里完成的操作中混合char
和double
是不好的做法?可能会有潜在的问题吗?
我猜测如果重量不在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;
}
答案 0 :(得分: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
。