假设我有3个变量:long
,int
和short
。
long l;
int i;
short s;
long lsum;
如果这是纯数学,由于乘法具有可交换属性,因此这些变量的顺序无关紧要。
l * i * s = i * s * l = s * i * l.
让lsum
成为这三个变量相乘的容器。
在C中,是否会出现这些变量的特定顺序导致不同结果的情况?
如果订单确实很重要,不一定是这个例子,那会是什么?
答案 0 :(得分:4)
由于整数促销,订单确实很重要。
当应用算术运算符时,如果其操作数的等级小于int
(例如int
或char
),则其每个操作数首先会提升为short
。如果其中一个操作数的排名仍然较高(例如long
),则提升的排名较小。
来自C standard的第6.3.1节:
2 如果可以使用int或unsigned int,则可以在表达式中使用以下内容:
具有整数类型(int或unsigned int除外)的对象或表达式,其整数转换等级小于或等于 int和unsigned int的等级。
_Bool,int,signed int或unsigned int类型的位字段。
如果int可以表示原始类型的所有值(限制为 通过宽度,对于位字段),该值被转换为int; 否则,它将转换为unsigned int。这些被称为 整数促销。所有其他类型的整数不变 促销。
从第6.3.1.8节开始:
如果两个操作数具有相同的类型,则不再进一步转换 需要的。
否则,如果两个操作数都有有符号整数类型或两者都有 无符号整数类型,操作数类型为较小的整数 转换等级转换为具有更大的操作数的类型 秩。
否则,如果具有无符号整数类型的操作数具有等级 那么,大于或等于另一个操作数的类型的等级 带有符号整数类型的操作数转换为 具有无符号整数类型的操作数。
否则,如果带有符号整数类型的操作数的类型可以 表示带有unsigned的操作数类型的所有值 整数类型,然后转换具有无符号整数类型的操作数 到带有符号整数类型的操作数的类型。
否则,两个操作数都将转换为无符号整数类型 对应于带有符号整数类型的操作数的类型。
作为示例(假设sizeof(int)
为4而sizeof(long)
为8):
int i;
short s;
long l, result;
i = 0x10000000;
s = 0x10;
l = 0x10000000;
result = s * i * l;
printf("s * i * l=%lx\n", result);
result = l * i * s;
printf("l * i * s=%lx\n", result);
输出:
s * i * l=0
l * i * s=1000000000000000
在此示例中,首先评估s * i
。 s
的值会提升为int
,然后会将两个int
值相乘。此时发生溢出,取消未定义的行为。然后,结果会提升为long
并乘以l
,结果为long
类型。
在后一种情况下,首先评估l * i
。 i
的值被提升为long
,然后两个long
值相乘,溢出不。然后将结果乘以s
,首先将其提升为long
。同样,结果不会溢出。
在这种情况下,我建议将最左边的操作数转换为long
,以便将所有其他操作数提升为该类型。如果您使用带括号的子表达式,您可能还需要在其中应用强制转换,具体取决于您想要的结果。
答案 1 :(得分:3)
是的,请参阅"类型转换"和"类型促销"在http://www.cplusplus.com/articles/DE18T05o/
mtcars %>%
mutate(
am = factor(am, labels = c("auto", "manual")),
vs = factor(vs, labels = c("V", "S"))
) %>%
filter(am == "auto") %>%
# mutate to drop bar while maintaining bar formatting
mutate(mpg = ifelse(vs == "S", mpg == 0, mpg)) %>%
ggplot(aes(x = am, y = mpg, fill = vs)) +
geom_col(position = position_dodge()) +
scale_y_continuous(limits = c(0,35)) +
scale_x_discrete(drop = FALSE)
R1 = 255 R2 = 13835056960065503487
r1反映出(a * b)首先使用类型至少与int一样长,并且结果是最长操作数类型,这是无符号的,因此结果是无符号的并且溢出。