Что происходит за кулисами, если параметр функции srand является отрицательным целым числом?

srand man говорит, что srand имеет параметр unsignd int, но при использовании без приведения компиляция не жалуется. Есть ли шанс пойти не так, если вы не используете cast с (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

Я предполагаю, что компилятор неявно преобразует переменную x типа int в 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

Итак, всегда отрицательные числа после преобразования будут вести себя так? Как мне позаботиться об этом?


person ViniciusArruda    schedule 31.08.2014    source источник


Ответы (2)


Он будет неявно преобразован, используя -Wconversion с gcc, и clang должен предоставить предупреждение об этом, clang выдает следующее предупреждение:

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

правила, используемые для этого преобразования, описаны в проекте стандарта C99. раздел 6.3.1.3 Целые числа со знаком и без знака, в котором говорится (выделено мной):

  1. Когда значение с целочисленным типом преобразуется в другой целочисленный тип, отличный от _Bool, если значение может быть представлено новым типом, оно не изменяется.

  2. В противном случае, если новый тип не имеет знака, значение преобразуется путем многократного добавления или вычитания на единицу больше максимального значения, которое может быть представлено в новом типе, пока значение не окажется в диапазоне нового типа. .49)

  3. В противном случае новый тип является знаковым и значение не может быть представлено в нем; либо результат определяется реализацией, либо выдается сигнал, определяемый реализацией.

Таким образом, для вашего первого примера -2, преобразованное в unsigned int, будет таким:

UINT_MAX + 1 + -2

который равен UINT_MAX - 1, это приводит к полезному свойству, что -1 всегда будет преобразовано в максимальное значение без знака для любого типа без знака, который вы используете.

Вы можете использовать limits.h, чтобы получить UINT_MAX.

Случай со знаком отличается и описан в параграфе 3 выше, он определяется реализацией, что означает, что компилятор решает, как поступить в этом случае, поэтому вам нужно прочитать документацию, если таковая имеется, чтобы понять, что будет случиться здесь. Например, раздел поведения, определяемый реализацией для целых чисел говорит об этом кейс:

  • Результат или сигнал, вызванный преобразованием целого числа в целочисленный тип со знаком, когда значение не может быть представлено в объекте этого типа (C90 6.2.1.2, C99 и C11 6.3.1.3).

    Для преобразования в тип ширины N значение уменьшается по модулю 2^N, чтобы оно находилось в пределах диапазона типа; сигнал не поднимается.

Таким образом, он обрабатывает подписанный случай так же, как и неподписанный, число просто зашкаливает, и это не вызывает возбуждение сигнала. Таким образом, для gcc это четко определенное поведение, но это не переносимое поведение, и поэтому на него не следует полагаться.

person Shafik Yaghmour    schedule 31.08.2014
comment
Еще один вопрос, который вы, возможно, знаете: я заметил, что подобное поведение возникает, когда я пытаюсь присвоить переменной int число, большее, чем она поддерживает. Итак, каков расчет, чтобы узнать, какое значение будет сохранено в переменной, в которой я пытался сохранить большее значение, чем оно поддерживает? Это поможет мне узнать, как это реализовано. - person ViniciusArruda; 31.08.2014
comment
Во-первых, спасибо за ссылку, мне очень поможет, но, извините за настойчивость, я читал документы, но не нашел чего-то, что показало бы, как хранится число, регистр больше, чем поддерживает тип. Я хотел бы что-то вроде сеанса 6.3.1.3, который подробно сообщает. - person ViniciusArruda; 01.09.2014
comment
Думаю, я понял. Я нашел в Интернете что-то, говорящее о целочисленном переполнении. Так, в данном случае, это то, что я имею в виду? Или целочисленное переполнение существует только тогда, когда задействована арифметика? целочисленное переполнение и неопределенное поведение - person ViniciusArruda; 01.09.2014

Я думаю, что ваша идея верна, потому что в заголовочном файле «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

Надеюсь, мой ответ будет вам полезен.

person David    schedule 31.08.2014