2015-07-16 1 views
3

Если я не инициализирую i, я не знаю его значения, но также не могу предсказать значение rand().Почему используется значение int i; неопределенное поведение, но с использованием значения rand() нет?

Но с другой стороны, я знаю значение неинициализированных i между INT_MIN и INT_MAX, и я знаю, значение rand() между 0 и RAND_MAX.

Почему используется значение uninitialised i undefined, но с использованием значения rand() нет?

+2

Значение неинициализированной локальной нестатической переменной * неопределено *. * Pseudo * -случайное число, возвращаемое 'rand', является детерминированным, если вы знаете текущее семя. –

+0

Даже если 'rand()' не генерирует предсказуемое число, во время работы оно является определенным числом, поэтому код ниже его может использовать. Это отличается от неинициализированного 'i'. – YuMS

ответ

5

Стандарт говорит, что чтение из неинициализированной переменной - это неопределенное поведение, так оно и есть. Вы не можете сказать, что это между INT_MIN и INT_MAX. На самом деле, не может действительно думать об этой переменной как о любом значении, поэтому вы не могли даже проверить эту гипотезу *.

rand() с другой стороны предназначен для создания случайного числа в пределах диапазона. Если чтение из результата rand() не было определено, оно не будет частью какой-либо библиотеки, потому что оно не может быть использовано.


* Обычно "неопределенное поведение" предоставляет возможности для оптимизации. Оптимизатор может делать все, что захочет, с неинициализированной переменной, работая в предположении, что он не читается.

+0

У меня нет стандарта под рукой, поэтому, возможно, вы можете пролить свет на это: Является ли 'int i;' * defined * выделять 'i'? I.e. - это * существование * неинициализированного 'i', четко определенного, даже если его содержимое не является? – DevSolar

+0

@DevSolar Я не уверен, что означает существование, если вы не можете читать это. Я думаю, вы можете получить его адрес, и его размер известен во время компиляции. Но чтение из него, что UB действительно означает, что все может случиться. Реализация может иметь представление ловушки, которое вызывает, например, сигнал. Я думаю, что здесь C++ отличается от C, где переменная может хранить неопределенное значение (IIRC, но мой C не так уж хорош.) – juanchopanza

+1

Нет, C99 (который является единственным стандартным документом, который у меня есть) также говорит о ловушных представлениях , Я соответствующим образом обновил свой ответ. – DevSolar

1

rand использует алгоритм генерации вашего номера. Так rand не определена и, если при использовании srand начать генерацию случайных чисел Вы выбираете значение, как 42, вы всегда будете получать то же значение каждый раз, когда вы запускаете приложение попытку запустить этот пример, вы увидите:

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

int main() 
{ 
    srand(42); 

    printf("%d\n", rand()); 
    return 0; 
} 

Смотри также: https://en.wikipedia.org/wiki/List_of_random_number_generators

7

значение неинициализированной переменной является неопределенным . Возвращаемое значение rand() равно , которое определяется как следующее число в псевдослучайной последовательности для данного семени.

relyrand(), возвращающий псевдослучайное число. Вы не можете полагаться на какую-либо характеристику значения неинициализированного int i.

Я искал стандарт C99 (ISO/IEC 9899: 1999), который является единственным стандартным документом, который у меня есть, но я серьезно сомневаюсь, что все это изменилось. В главе 6.2.6 Представления типов указано, что целые числа могут быть сохранены в памяти с битами заполнения, значение которого равно неуказанным, но может содержать биты четности, которые будут установлены после инициализации и любая арифметическая операция над целым числом. Некоторыми представлениями (например, несоответствие четности) могут быть ловушечные представления, поведение которых равно undefined (но вполне может прекратить вашу программу).

Так, нет, вы даже не можете полагаться на неинициализированного int i быть INT_MIN < = i < = INT_MAX.

+1

Но можем ли мы даже полагаться на 'INT_MIN' <=' i' <= 'INT_MAX'? Он не должен терпеть крах, но он может очень хорошо, не так ли? Есть и другие вещи, которые компилятор может испортить, я думаю. –

+0

@ RaphaelMiedl: Мне нужно будет искать главу и стих стандарта, но я бы сказал, что 'int i;' is * defined * выделяет 'i', и, следовательно, там должно быть что-то *. То есть, это * содержимое * из 'i' не определено, а не * существование *' i' ... тогда снова я обычно * хорошо * очищаюсь от любого UB, потому что компилятор ** является ** в чтобы делать смешные вещи, если вы этого не сделаете. ;-) – DevSolar

+1

@RaphaelMiedl: Я * * посмотрел главу и стих, и ты прав. – DevSolar

2

Значение rand определено как случайное. Значение неинициализированной переменной не определено ничем. В этом и заключается разница, является ли что-то значимым чем-то значимым (в то время как rand() также имеет смысл - он дает (псевдо) случайные числа) или не определен.

2

Короткий ответ, как и другие, сказал, что стандарт говорит так.

Акт доступа к значению переменной (описанный в стандарте как выполнение преобразования lvalue в rvalue), который не инициализирован, дает неопределенное поведение.

rand() определяется как дает значение от 0 до RAND_MAX, где RAND_MAX (макро объявлен в <cstdlib> для C++, и <stdlib.h> для C) задается как имеющий значение, которое, по меньшей мере 32767.

1

Рассмотрим переменную x в следующем коде:

uint32_t blah(uint32_t q, uint32_t r) 
{ 
    uint16_t x; 
    if (q) 
    x=foo(q); // Assume return type of foo() is uint16_t 
    if (r) 
    x=bar(r); // Assume return type of bar() is uint16_t 
    return x; 
} 

Так как код никогда не присваивает x значение вне диапазона 0-65535, компилятор для 32-битного процессора может законно выделять 32-битный регистр для Это. Действительно, поскольку значение q никогда не используется после первого использования x, компилятор может использовать тот же регистр для хранения x был использован для хранения q. Обеспечение того, чтобы функция всегда возвращала значение 0-65535, потребовало бы добавления некоторых дополнительных инструкций по сравнению с простой возможностью вернуть все, что попадало в регистр, выделенный для x.

Обратите внимание, что с точки зрения стандартных авторов, если стандарт не будет требовать, чтобы компилятор сделать x содержать значение от 0-65535, это может также не указывать ничего о том, что может если код пытается использовать x. Реализации, которые желают предоставить какие-либо гарантии поведения в таких случаях, свободны в этом, но Стандарт не предъявляет никаких требований.