如果srand函数的参数是负整数,那么在幕后会发生什么?

3
说,srand的参数是一个无符号整型,但是如果不强制转换使用,编译器不会报错。 如果不使用(unsigned int)进行类型转换,有可能出现问题吗?或者没有区别,因为编译器总是会隐式地转换? 下面是一个例子:

#include<stdio.h>
#include<stdlib.h>

int
main(void)
{
    int num, x;

    x = -2;

        srand(x);
    num = rand() % 100000;

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

    return 0;
}

这段代码的输出结果是:
32

我将假设编译器会自动将类型为int的变量x转换为unsigned int。这种转换会发生什么? 如果转换将变量(其类型为int)转换为与另一个数字相同的unsigned int,那么会怎样? 当生成种子后,它们将是相同的。 换句话说:

int x = -2;
int y = 546; // the number 546 is just an example !

int num_x = srand(-2);
int num_y = srand(546);

在幕后,num_x等于num_y

当我在我的srand参数上有一个负数时,这个疑问出现了,我怀疑这个种子是否唯一。我认为不是,因为例如下面的代码:

#include<stdio.h>
#include<stdlib.h>

int
main(void)
{
    int t, num;
    t = -6;

    printf("%u\n", t);  // prints the variable t as unsigned (implicitly converted)
        srand(t);
    num = rand() % 100000;
    printf("Random number: %d\n", num);

    srand(4294967290);   // the number 4294967290 is how the int number -6 looks like when converted in unsigned int
    num = rand() % 100000;
    printf("New random number: %d\n", num);
    return 0;
}

它的输出:
4294967290
Random number: 19
New random number: 19

所以,转换后的负数总是会表现出这种行为吗? 我该如何解决这个问题?

2个回答

3

它将会被隐式转换,使用gcc的-Wconversion,clang应该会对此提供警告,clang给出以下警告:

warning: implicit conversion changes signedness: 'int' to 'unsigned int' [-Wsign-conversion]
    srand(x);
    ~~~~~ ^

这种转换所使用的规则在C99标准草案的第6.3.1.3有符号和无符号整数中有规定(强调是我的):
  1. 当将具有整数类型的值转换为其他整数类型时,如果该值可以用新类型表示,则其值不变,除非新类型是_Bool。

  2. 否则,如果新类型是无符号的,则通过反复添加或减去一个比新类型中可表示的最大值多1的值,直到该值在新类型的范围内,来对该值进行转换。49)

  3. 否则,新类型为有符号的,而该值不能用它来表示;结果是实现定义的,或引发实现定义的信号。

因此,对于您的第一个例子,将-2转换为unsigned int,结果应为:
UINT_MAX + 1 + -2

这里的UINT_MAX - 1代表的是无符号整数类型中的最大值减去1,这导致了一个有用的特性:无论您使用的是哪种无符号类型,-1将始终被转换为最大的无符号数值。

您可以使用limits.h来获取UINT_MAX

有符号情况则不同,根据上面的第3段所述,它是实现定义的,这意味着编译器决定如何处理此情况,因此您必须阅读相关文档(如果有提供)以了解此处会发生什么。例如,整数的实现定义行为部分针对此情况表示:

  • 在将整数转换为无法表示为该类型对象的有符号整数类型时,结果或引发的信号(C90 6.2.1.2,C99和C11 6.3.1.3)。

    对于转换为宽度为N的类型,超出类型范围的值被模数2^N减少,以使其在类型范围内;不引发信号。

所以它将有符号情况视为无符号情况,数字只是重复并且不会导致引发信号。因此,对于gcc而言,这是定义明确的行为,但这不是可移植的行为,因此不应该依赖它。


还有一个问题你可能知道,我观察到当我尝试给一个int变量赋一个超过它支持的数字时,会出现类似的行为。那么,如何计算出在我尝试存储一个超过其支持范围的值的变量中将存储什么值?这将帮助我了解它是如何实现的。 - undefined
首先感谢提供的链接,这对我帮助很大。但是,非常抱歉我还是要再次强调一下,我已经阅读了相关文档,但没有找到关于当数字超过类型支持范围时如何存储的内容。我希望能够得到类似于第6.3.1.3节中详细说明的内容。 - undefined
我认为我理解了。我在网上找到一些关于整数溢出的内容。那么,在这种情况下,这就是我的意思吗?或者只有在涉及算术运算时才会出现整数溢出?整数溢出未定义行为 - undefined

0
我认为你的想法是正确的,因为在头文件"stdlib.h"中,srand函数的声明是:
void srand (unsigned int seed);

因此,如果你将一个负整数作为参数传递给srand函数,srand函数会将这个负整数转换为无符号整数。

以下是一个示例:

#include<stdio.h>
#include<stdlib.h>

int test(unsigned int data)
{
    if(data == 4294967290)
    {
        return 1;
    }
    else
        return 99;
}
int
main(void)
{
    int i;

    i = -6;
    printf("negative parameter : %d\n", test(i));

    i = 4294967290;
    printf("unsigned parameter : %d", test(i));


    return 0;
}

它的输出:

negative parameter : 1
unsigned parameter : 1

希望我的回答对你有用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接