两个为 true 的变量在 (tmp1 == tmp2) 中返回 false.为什么

Two variables that are true return false in (tmp1 == tmp2). Why?

本文关键字:tmp2 返回 为什么 false tmp1 变量 两个 true      更新时间:2023-10-16

我刚刚遇到了一个问题。我想比较一下我的埃拉托斯特尼斯筛子是否包含质数。在代码中我有这一行

if (sieve[2] == is_prime(2)) // returns false
    printf ("true");

现在,sieve[2] 是一个布尔值,它的值是真的(我什至检查了数组,所以毫无疑问(。 is_prime(2( 也是一个布尔值(我也检查过(。

现在我的问题。上面显示的行返回 false。是的 - 即使它的语句是:

if ( true == true )  // which normally returns true
    printf ("true");

但是,在删除一个等式符号后:

if ( sieve[2] = is_prime(2) ) // returns true
    printf ("true");

此语句返回 true。

有人可以简要解释一下在这种情况下,与==相比,一个方程标记是如何工作的吗?

提前致谢

编辑

is_prime:

bool is_prime(int x) {
    unsigned int i,j,k;
    if (x < 2) return false;
    else {
        for (i=2; i!=x; i++) {
            if (x == i) return true;
            else if (x % i == 0) return false;
        }
    }
}

筛:

const int n = 10000;
bool sieve[n+1];
.
.
unsigned long int i;
sieve[0] = sieve[1] = false;
for (i=2; i<=n; i++) sieve[i] = true;
for (i=2; i*i<=n; i++) {
    if (sieve[i]) {
        unsigned tmp = 2*i;
        while (tmp <= n) {
            sieve[tmp] = false;
            tmp += i;
        }
    }
}

[编辑2]问题出在"is_prime(x("上 将循环条件从"i!=x"更改为"i<=x"很抱歉给您带来麻烦,并感谢您的回答

更新

bool is_prime(int x) {
    unsigned int i,j,k;
    if (x < 2) return false;
    else {
        for (i=2; i!=x; i++) {
            if (x == i) return true;
            else if (x % i == 0) return false;
        }
    }
}

您的is_prime()(上图(被破坏,具有未定义的行为,例如当x2(或任何实际的素数(时,它会在没有return语句的情况下到达函数的末尾 - i!=x测试意味着循环内的x == i永远不会true

is_prime(2)它可能会返回有效的随机结果(基于剩余的堆栈或寄存器内容/在您记录的输出中,它似乎x本身"返回",大概是因为您的 ABI 使用相同的 CPU 寄存器或堆栈地址传入参数并传回函数的返回值(。

具体来说对于 2,流进入第一个 else 子句,然后i=2第一个i!=x测试失败,for循环立即退出......在for的范围之后没有return。 最小更正的代码(可以实现更快的实现,但保持简单性和预期的逻辑(:

bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i < x; ++i)
         if (x % i == 0)
             return false;
    return true;
}

等效性/==

使用 sieve[2] == is_prime(2) 它会检查它们具有相同的值 - 可能在转换其中一个值以启用比较之后,但您说它们都是布尔值,所以没有必要。 这将在iftrue或都false时产生"true"值。

现在我的问题。上面显示的行返回 false。是的 - 即使它返回 false...

这没有任何意义...我建议您在 if 语句之前添加以下内容以检查变量的值:

std::cout << "sieve[2] " << sieve[2] << " (bool)" << (bool)sieve[2]
      << ", is_prime(2) " << is_prime(2) << std::endl;

我什至签入了数组,所以毫无疑问

警惕错误,例如看到数组内容显示 ala { true false true false } 并认为[2]是第二个值......它实际上是第三个。因为数组索引从 0 开始。

分配/=

使用sieve[2] = is_prime(2),您将is_prime(2)的值分配给sieve[2],并且如果该值在布尔上下文中被视为为真,则if语句被视为"true"(即它是值为true的布尔值,或非0数字或指针等(。 对于大多数数据类型,if (sieve[2] = is_prime(2)) ...的执行流程与简单的if (is_prime(2)) ...相同,但当然它也修改了sieve[2]

它将右侧操作数分配给左侧操作数,并返回左侧操作数。由于您正在为变量赋值 true,因此它的计算结果为 true。如果将变量设置为 false ,则不会获得输出,例如:

bool x;
if(x = false) 
    printf("this won't be printed");

在这里,等于影响左运算符与右运算符的值,然后测试该值。因此,结果必须是正确运算符的值。

您在

is_prime 中的循环永远不会运行检查x == i为真,因为它运行的时间只要 x != i .这两个条件是相互排斥的。

这意味着函数将在没有 return 语句的情况下结束,这会导致未定义的行为

if ( sieve[2] = is_prime(2) )

包含作业,而不是比较。
由于赋值的值是分配的值,因此无论何时is_prime(2)都是如此。

但是,让我们看看您的is_prime,看看如果我们将其传递2会发生什么......

bool is_prime(int x) {
    unsigned int i,j,k;

到目前为止,一切顺利,但jk从未使用过,所以它们不应该真的在这里。

    if (x < 2) return false;
2

不小于 2,所以我们将继续...

    else {
        for (i=2; i!=x; i++) {

好的,设置i = 2,并将其与x进行比较,这是2,并且......哎呀,i等于x,所以我们立即放弃循环...

            if (x == i) return true;
            else if (x % i == 0) return false;
        }
    }

。然后在这里失败,我们没有像我们承诺的那样返回值,并导致未定义的行为。

}

所以,你的程序是未定义的(你真的应该打开编译器警告,或者开始侦听它们(。
这发生在每个素数上。

你可以像这样重写循环:

    for (i=2; i <= x; i++) {
        if (x == i) return true;
        else if (x % i == 0) return false;
    }

    for (i=2; i < x; i++) {
        if (x % i == 0) return false;
    }
    return true;

为什么if (is_prime(2))似乎有效?

(由于此代码未定义,因此以下内容主要是推测,应仅使用适当的盐量来执行。

通常,当一个函数应该返回

一些东西但没有返回时,调用函数将只获取存储在返回值应该在的位置的任何内容并使用它。
在这种情况下,这个值很可能与表示true的位模式不同,因此将比较不等于true,在if (is_prime(2) == true)
但是,它也很可能不是表示false的位模式,因此在有条件的if(is_prime(2))中将被视为true