Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > C/C++ программирование > Общие вопросы C/C++
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 01.03.2012, 17:03   #1
Стремящийся
Форумчанин
 
Аватар для Стремящийся
 
Регистрация: 01.11.2011
Сообщений: 172
По умолчанию Не пойму оператор ","(запятая)

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

У меня такой вопрос: почему при таком выражении

int x=(1,010);

cout<< x;// результат 8

а при таком

int x=1,010;

cout<< x;// результат 1

Мне вчера сказали, что х присваевается 010, потому что оператор "," работает слева направо, не до конца понимаю почему х присвается не 1, а 010.
Заранее благодарен.

Модераторам: просьба не удалять тему сразу, а пусть поживет пару дней
Желание тысяча возможностей, нежелание - тысяча причин
Стремящийся вне форума Ответить с цитированием
Старый 01.03.2012, 17:05   #2
Стремящийся
Форумчанин
 
Аватар для Стремящийся
 
Регистрация: 01.11.2011
Сообщений: 172
По умолчанию

Извиняюсь перед модераторами, нашел вчерашнюю тему
Желание тысяча возможностей, нежелание - тысяча причин
Стремящийся вне форума Ответить с цитированием
Старый 01.03.2012, 17:28   #3
Стремящийся
Форумчанин
 
Аватар для Стремящийся
 
Регистрация: 01.11.2011
Сообщений: 172
По умолчанию

Как посоветовали модераторы я почитал книгу, но там написано, что этот оператор всегда берет правое значение, а почему не объясняют, может надо принять как есть?
Желание тысяча возможностей, нежелание - тысяча причин
Стремящийся вне форума Ответить с цитированием
Старый 01.03.2012, 19:24   #4
Granus
С++
Форумчанин
 
Аватар для Granus
 
Регистрация: 22.09.2008
Сообщений: 791
По умолчанию

Цитата:
а почему не объясняют
Да потому что нет никакого почему, создатели языка решили, что так будет, и так и стало.
Форматируйте код, будьте людьми.
Granus вне форума Ответить с цитированием
Старый 01.03.2012, 20:34   #5
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от Стремящийся Посмотреть сообщение
Как посоветовали модераторы я почитал книгу, но там написано, что этот оператор всегда берет правое значение, а почему не объясняют, может надо принять как есть?
Это правило языка. Вот есть правило: жи/ши пиши с буквы "и".
А есть правило, которому подчиняется оператор запятая.

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

Иногда бывают ситуации, когда результат вычисления выражения зависит от каких то предварительных действий. При этом, совершить эти действия требуется в контексте самого выражения. И разбивать контекст на "предварительные действия" и "само действие" либо невозможно, либо очень не удобно.

Привожу простой пример ситуации, где оператор запятая оказался очень кстати:

Предположим, тебе в твоих программах частенько требуется генератор случайных чисел, который возвращал бы тебе случайное число из диапазона от least до greatest включительно.

Обыкновенно для этих целей используют стандартный ГСЧ. Для этого, сначала инициализируют его:
Код:
srand(  (size_t) time(NULL) ) ;
А потом уже, либо используют по месту rand()%плюшки
Что не красиво, потому что каждый раз приходится рассчитывать формулу диапазона заново.

Либо используют формулу, типа:
Код:
int random(int least, int greatest) {  return rand() % (greatest - least) + least; }
Но в последнем случае, программисту придётся не забывать проконтролировать тот факт, что ГСЧ уже проинициализирован:
Код:
srand(  (size_t) time(NULL) );
И при этом очень важно проконтролировать в ручную, что факт инициализации был только один раз. Что не есть удобно. а в многофайловом проекте и вовсе - гемморойно.

В этом случае, можно пойти на хитрость, написав вот так:

Код:
int InitRand() { srand(  (size_t)time(NULL)  ); return 0; } //инициализация ГСЧ
int random(int least, int greatest) 
{
    static int seed(  InitRand() ); 
    return rand() % (greatest - least) + least;
}
Здесь, внутри функции random инициализируется статическая переменная. По правилам языка, статики инициализируются лишь один раз, а время их жизни - до конца программы.

Причем, инициализируется переменная результатом, который вернёт функция InitRand(), а эта функция, в свою очередь инициализирует сам гсч

Таким образом, уже не нужно в ручную инициализировать ГСЧ, и контролировать, что бы инициализация была только один раз.

Можно сразу пользоваться функцией random(), и наслаждаться плодами цивилизации.

Последний раз редактировалось _Bers; 01.03.2012 в 21:04.
_Bers вне форума Ответить с цитированием
Старый 01.03.2012, 20:34   #6
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Однако! Для того, что бы организовать автоматическую анициализацию ГСЧ, нам пришлось завести отдельную функцию InitRand().

А для такой простой задачи отдельная функция совершенно не нужна.
И не зачем засорять глобальное пространство имен. И ух тем более, в глобальном (общедоступном) месте не должна находится функция, ничайный вызов которой сломает всю идею безопасной автоматической инициализации.

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

Другими словами, функцию InitRand() нужно поместить вовнутрь функции random(). Внутри random() произойдёт однократная инициализация ГСЧ, и никто снаружи не будет иметь к этой автоматике доступа.

Для одноразовых операций заводить отдельную функцию так же нет никакой нужды. И вот здесь, оператор запятая оказывается очень кстати:

Код:
//генератор сл. чисел
int random(int least, int greatest)
{
    static int seed(  (srand(  (size_t)time(NULL)  ), 0)  );    //инициализируется только один раз 
    return rand() % (greatest - least) + least;
}
Статическая переменная seed инициализируется только один раз.
Вопрос: чем она инициализируется?

Выражение, стоящее в скобочках выглядит так:
Код:
(srand(  (size_t)time(NULL)  ), 0)
То есть, переменная инициализируется результатом того, что находится в главных скобочках.

А там находится:
Код:
srand(  (size_t)time(NULL)  ), 0
Сначала запустится, и отработает srand( (size_t)time(NULL) )
Собственно это и есть автоматическая инициализация ГСЧ.

Но результатом всего выражения по правилу оператора запятая - то, что справа. А справа нолик.

Таким образом, результат всего этого выражения - ноль.

Поэтому, выражение:
Код:
static int seed(  (srand(  (size_t)time(NULL)  ), 0)  );
Свернётся в:

Код:
static int seed( 0 );
Таким образом, переменная seed будет проинициализирована только один раз за все время жизни программы. А значит, автоматика гарантированно сработает тоже только один раз.

При этом, для реализации рандома, не пришлось заводить дополнительных глобальных функций. И никто снаружи не имеет доступа к механизму её автоматики.

Осталось дело за малым: в многофайловом проекте в хэдэрах нельзя объявлять и определять функции. Нужно, что бы в хэдэрах были только прототипы, а в спп - реализации. Но ради одной малюсенькой функции заводить отдельную пару h/cpp откровенно лень.
И хочется запихать и объявление, и реализацию целиком в какой нибудь хэдэр.

Сделать это без конфликтов многократного переопределения можно с помощью свойства шаблонов (шаблоны позволяют пихать все в один хэдэр)

Код:
template<class TypeVal> int random(TypeVal least, TypeVal greatest)
{    //инициализируется только один раз 
    static int seed(  (srand(  (size_t)time(NULL)  ), 0)  );   return rand() % (greatest - least) + least; }
Теперь можно подключать хэдэр, где живет эта функция в любой единице трансляции проекта, и спокойно пользоваться. И не париться насчет инициализаций ГСЧ.

Последний раз редактировалось _Bers; 01.03.2012 в 20:39.
_Bers вне форума Ответить с цитированием
Старый 01.03.2012, 20:48   #7
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 914
По умолчанию

Цитата:
Сделать это без конфликтов многократного переопределения можно с помощью свойство шаблонов
Свой пятачок вставлю... )
Можно саму random объявить как static, ну чтоб без шаблонов.
EUGY вне форума Ответить с цитированием
Старый 01.03.2012, 21:00   #8
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от EUGY Посмотреть сообщение
Свой пятачок вставлю... )
Можно саму random объявить как static, ну чтоб без шаблонов.
Область видимости глобального статика - пределы единицы трансляции.
Если сделать функцию (или переменную) статической, то каждая единица
трансляции получит собственную уникальную копию сущности.


То есть, если тебе нужно, что бы на весь проект была создана только одна версия функции - можно сделать её шаблонистой, либо определять реализацию в файле cpp

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

Однако! При этом нужно учитывать, что каждая копия статической функции породит свою копию статик переменной.
И при этом каждая копия статичесой переменой выполнит свою одноразовую инициализацию.

Таким образом, функция:
Код:
srand(  (size_t)time(NULL)  )
Будет вызвана столько раз, сколько копий функции random было понаделано для каждой единицы трансляции.

Итого: вместо гарантированной однократной инициализации, получишь гарантировано многократную.

Ты уверен, что это именно то, что тебе было нужно?
_Bers вне форума Ответить с цитированием
Старый 01.03.2012, 21:10   #9
EUGY
Форумчанин
 
Аватар для EUGY
 
Регистрация: 11.07.2010
Сообщений: 914
По умолчанию

Цитата:
Ты уверен, что это именно то, что тебе было нужно?
Если необходимо, то да.

ps. Например генерирование уникального номера (типа rtti) для класса

Последний раз редактировалось EUGY; 01.03.2012 в 21:16.
EUGY вне форума Ответить с цитированием
Старый 01.03.2012, 21:15   #10
_Bers
Старожил
 
Регистрация: 16.12.2011
Сообщений: 2,329
По умолчанию

Цитата:
Сообщение от EUGY Посмотреть сообщение
Если необходимо, то да.
А в каких случаях это может быть необходимым?

Конкретно:

1. В каких случаях может быть необходимо каждой ед. трансляции иметь уникальную копию глобальной переменой?

2 В каких случаях может быть необходимо каждой ед. трансляции иметь уникальную копию обычной функции?
_Bers вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Как можно заменять "запятая" на "Enter" Silent-cry Microsoft Office Word 4 26.01.2018 12:03
Вывести название соответствующей карты вида "шестерка бубен", "дама червей","туз треф" и т.п. воваава Помощь студентам 3 01.12.2011 12:50
Как обойти "преобразование типа из "string" в "float" невозможно" lexluter1988 Помощь студентам 1 07.08.2010 12:23
при вводе на листе "магазин"- код товара появлялось "описание" товара из "склада" с "продажной ценой" aleksei78 Microsoft Office Excel 13 25.08.2009 12:04