预处理器常量溢出?

时间:2014-08-02 20:10:38

标签: c c-preprocessor

我使用Arduino Uno(16位int)和:

#define DT 49
#define DT_MICRO ((DT) * 1000)
...
while (val<DT_MICRO){/*something*/}

哪个给

49
-16536

如果我使用Serial.print(DT);打印它们。为什么?我期待49000.为什么会出现负数?如果我使用(在代码中)Serial.print(DT*1000)

,也会发生同样的情况

使用

DT 49L
and DT_MICRO (DT*1000L)

像预期的那样工作。谢谢你的澄清。

3 个答案:

答案 0 :(得分:4)

#if指令外,预处理器不执行算术,只执行文本替换。在编译器的后续阶段看到之前,代码中的任何DT_MICRO都会被序列((49) * 1000)替换。

常量491000属于int类型。 (更一般地,整数常量的类型为intlong intlong long int,具体取决于其值; 491000保证适合一个int,这是他们的类型。)

因此,表达式((49)*1000)也是int类型。对于表达式(与常量相对),类型不受值的影响。如果49,000太大而不适合int,那么表达式会溢出。

类型int必须至少为16位,上限至少为32767.这些天更为常见的是32位,上限为2,147,483,647(2 31 -1)。因此,如果int是16位,则DT_MICRO具有未定义的行为,但很可能会评估为-16536,这就是您所看到的。如果int为32位,则DT_MICRO的评估结果为49000

至于为什么你会看到负值,你没有给我们足够的信息来确定。你说你“打印”了价值,但是怎么样?打印它的正确方法是:

printf("%d\n", DT_MICRO);

但是你可以做很多其他事情。

如果您需要确保DT_MICRO类型足以保持其值,您可以将定义更改为:

#define DT 49L
#define DT_MICRO (DT * 1000L)

(请注意,只要DT被正确定义,就不需要DT周围的额外括号。这导致它为long类型,至少为32位,您可以使用以下方式打印它:

printf("%ld\n", DT_MICRO);

答案 1 :(得分:1)

预处理器无法将常量解释为一种或另一种类型,它只能进行词法替换...所以你的程序将完全相同:

print(49*1000)

并且那些被视为.c文件中的裸常量,因此在不知道print()的原型是什么的情况下,除了指示您远离预处理器之外,我无法提供更多帮助。

答案 2 :(得分:0)

数字为负的原因是您使用的是16位带符号数学运算。您可以表示的最大正数是32767.任何大于该值的数字都被视为负数。如果您想了解有关有符号整数数学的更多信息,可以在线获取大量资源。

要计算更大的值,您需要使用不同的变量类型。