#define和声明之间有什么区别

时间:2013-03-06 17:06:09

标签: c

#include <stdio.h>
#include <math.h>

// #define LIMIT 600851475143
int isP(long i);
void run();
// 6857
int main()
{
    //int i = 6857;
    //printf("%d\n", isP(i));
     run();
}

void run()
{
long LIMIT = 600851475143;
// 3, 5
// under 1000

long i, largest =1, temp=0;
for(i=3; i<=775147; i+=2)
{
    temp = ((LIMIT/i)*i);
if(LIMIT == temp)
    if(isP(i)==1)
            largest = i;
}
printf("%d\n",largest);
}

int isP(long i)
{
long j;
for(j=3; j<= i/2; j+=2)
    if(i == (i/j)*j)
        return 0;

return 1;

}

我刚遇到一个有趣的问题。如上所示,这段代码用于计算LIMIT的最大素数。上面显示的程序给了我29的答案,这是不正确的。

虽然奇迹般地,当我定义LIMIT值(而不是将其声明为长)时,它可以给我正确的值:6857。

有人可以帮我弄清楚原因吗?非常感谢!

6 个答案:

答案 0 :(得分:3)

许多平台上的long是一个4字节整数,并且会在2,147,483,647溢出。例如,请参阅Visual C++'s Data Type Ranges页面。

当您使用#define时,编译器可以自由选择一种更合适的类型,它可以保存非常大的数字。这可能会使其表现正常,并为您提供您期望的答案。

但是,一般情况下,我建议明确说明数据类型,并选择能够正确表示数字的数据类型,如果可能的话,不需要编译器和平台特定的行为。

答案 1 :(得分:1)

我怀疑这里有数字类型问题。

#define是一个预处理程序指令,因此在运行编译器之前,它会在代码中用该数字替换LIMIT。这使得编译器可以打开门来解释它想要的数字,这可能不是long

在您的情况下,long可能不够大,因此编译器在您使用#define时会选择其他内容。对于一致的行为,您应该指定一个您知道具有适当范围的类型,而不是依赖编译器进行正确猜测。

您还应该在编译器上启用完整警告,它可能能够为您检测到这类问题。

答案 2 :(得分:1)

输入如下表达式时:

(600851475143 + 1)

一切都很好,因为编译器会自动将这两个常量提升到适当的类型(例如你的long long),足以执行计算。您可以通过这种方式执行任意数量的表达式。但是当你写道:

long n = 600851475143;

编译器尝试将long long(或任何常量被隐式转换为)分配给long,这会导致您的案例出现问题。你的编译器应该警告你这个,gcc例如说:

warning: overflow in implicit constant conversion [-Woverflow]

当然,如果long大到足以容纳该值,则没有问题,因为常量将是与long相同或更小的类型。

答案 3 :(得分:0)

可能是因为600851475143大于LONG_MAX(根据this 2147483647)

答案 4 :(得分:0)

尝试用'long long'替换限制类型。它的方式,它包裹(尝试打印限制为长)。预处理器知道并使用正确的类型。

答案 5 :(得分:0)

您的代码基本上可以减少这两种可能性:

long LIMIT = 600851475143;
x = LIMIT / i;

VS

#define LIMIT 600851475143
x = LIMIT / i;

第一个相当于将常量强制转换为long

x = (long)600851475143 / i;

而第二个将被预编译成:

x = 600851475143 / i;

这就产生了不同之处:600851475143对于编译器的long类型来说太大了,所以如果它被强制转换为long,它会溢出并变得疯狂。但如果直接在分区中使用它,编译器就知道它不适合long,自动将其解释为long long字面值,i被提升并且除法以long long完成。

但请注意,即使算法似乎在大多数情况下都能正常工作,您仍然会在其他地方出现溢出,因此代码不正确。您应该将任何可能包含这些大值的变量声明为long long