Здравствуйте, Erop, Вы писали:
E>>>Даже там оно так непоследовательно сделано... Когда индексируешь вектор, то беззнаковое, а когда итератор произвольного доступа, то вроде бы знаковое... E>>>Или ты и difference_type за беззнаковое держишь? BFE>>Я крайне редко использую разницу между указателями. И обычно я знаю какой из итераторов больше.
E>При чём тут ты и STL? Я про то, что в
(1) и (2) не эквивлентны, если для mtPos важна знаковость...
Вообще-то (если подумать) всё логично и последовательно. (1) — unsigned (2) — signed (при условии, что numeric_limits<size_t>::max() <= numeric_limits<difference_type>::max())
E>Так что реальных гарантий, в математическом смысле, STL-код всё рвно не даёт. Там, конечно, везде нарисованы unsigned, но если ты начнёшь этот "запасной" битик реально юзать, то имеешь большие шансы таки нарваться...
Я тут полез опять смотреть стандарт и узнал, что даже арифметика с обычными указателями не защищена от arithmetic overflow и undefined behavior (5.7/5 и 5.7/6).
Т.е. можно (теоретически) создать такой массив, что к некоторым элементам этого массива нельзя доступиться через arr[myPos] если myPos имеет тип std::ptrdiff_t. Более того, если вычесть указатель на первый элемент массива из указателя на последний элемент массива, то можно arithmetic overflow обрести. Впрочем, авторы стандарта за всё это безобразие перекладывают ответственность на плечи разработчиков компилятора.
BFE>>Потому, что это стандарт : E>И что с того? Это же стандарт наа библиотеку, а не на образ мысли?
Наl стандартом столько лет трудилось много умных людей. Почему бы не воспользоваться результатами этого труда, казалось бы.
Здравствуйте, B0FEE664, Вы писали:
BFE>Вообще-то (если подумать) всё логично и последовательно. (1) — unsigned (2) — signed
Только не поняятно, на кой эти все красоты тут нужны. Цель-то в чём? Поддержать массив длинной 0хС0000000? Так это сделать всё равно не удалось...
А то ведь, при таком подходе, надо вообще всем числам в программе приписать какие-то размерности и строго следить что какого типа объявлять. Но так обычно не делаают, и IMHO, правильно делают, что не делают
BFE>(при условии, что numeric_limits<size_t>::max() <= numeric_limits<difference_type>::max())
Ага-ага. И часто ты встречал реализации, где это усовие соблюдаеся?
BFE>Я тут полез опять смотреть стандарт и узнал, что даже арифметика с обычными указателями не защищена от arithmetic overflow и undefined behavior (5.7/5 и 5.7/6). BFE>Т.е. можно (теоретически) создать такой массив, что к некоторым элементам этого массива нельзя доступиться через arr[myPos] если myPos имеет тип std::ptrdiff_t. Более того, если вычесть указатель на первый элемент массива из указателя на последний элемент массива, то можно arithmetic overflow обрести. Впрочем, авторы стандарта за всё это безобразие перекладывают ответственность на плечи разработчиков компилятора.
Дык вся идея с беззнаковым size_t и погоней за битиком, изначально была тухлая и нежизненная...
BFE>Над стандартом столько лет трудилось много умных людей. Почему бы не воспользоваться результатами этого труда, казалось бы.
Ну, уж в чём, в чём, а в области древних частей стандартной библиотеки, таких как потоки или size_t, С++ является редкостным уродом...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, B0FEE664, Вы писали:
BFE>Это "идеологически верно".
Эти слова не значат вообще ничего.
Можешь хоть как-то обрисовать профит?
E>>Цель-то в чём? Поддержать массив длинной 0хС0000000? Так это сделать всё равно не удалось...
BFE>Цель, видимо, указать, что это принципиально два разных типа: размер не может быть отрицательным, в отличии от смещения.
Зачем это указывать? Почему, например, для синусов не заводят тип "целое с плавающей точкой от -1 до 1", а для sizeof'а заводят таки специальный size_t?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
BFE>>Это "идеологически верно". E>Эти слова не значат вообще ничего. E>Можешь хоть как-то обрисовать профит?
Ну какой может быть профит от идеологических установок? Профит только в том, что легче понять почему так, а не иначе.
E>>>Цель-то в чём? Поддержать массив длинной 0хС0000000? Так это сделать всё равно не удалось... BFE>>Цель, видимо, указать, что это принципиально два разных типа: размер не может быть отрицательным, в отличии от смещения. E>Зачем это указывать?
Для ясного понимания.
E>Почему, например, для синусов не заводят тип "целое с плавающей точкой от -1 до 1", Целое с плавающей точкой ? Это как?
Почему не заводят? Некоторые заводят. Причём это может быть сделано из двух разных соображений:
1) для ленивых вычислений
2) для увеличения точности — число с фиксированной точкой от -1 до 1
Но на практике такое встречается редко.
E>а для sizeof'а заводят таки специальный size_t?
видимо, чтобы не ограничивать возможность реализации "лишними" соглашениями
Здравствуйте, Аноним, Вы писали:
А>Приветствую.
А>- Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет использоваться в качестве индексации масива / контейнера, зачастую используется знаковая целочисленная переменная? А>Нет, ну я понимаю, что size_t многим просто не нужен — пишу себе под 32 бита и буду писать, думают они.
Есть у size_t одна неприятность, когда это возвращаемое значение и нам надо вернуть еще признак ошибки. В случае знакового целого я верну -1 и не буду париться. Поэтому есть size_t, а есть ssize_t. А еще, бывает, надо из одного size_t вычесть другой, где отрицательный результат тоже имеет смысл.
Имхо, беззнакомый size_t это наследие 16-битных платформ, в частности DOS. Тут жертвуя старшим битом мы из 64k получаем 32k, что ощутимо неприятно. Уже на 32-битных платформах разница межу 2G и 4G не играет большой роли. Ситуация, когда надо именно 3G, но при этом заведомо меньше 4G, экзотична. А в случае 64-бит пожертвовать одним битом еще более не жалко. Отрицательные числа их же не зря ввели, они естественных образом получаются из целых.
Беззнаковые хороши для битовый масок, когда операции сложения и вычитания используются только во всяких битовых хаках а-ля (x^(x-1)+1)>>1 при которых результат остается беззнаковым. Вообще, для таких случае рулят модульные типы Ada.
Здравствуйте, B0FEE664, Вы писали:
BFE>>>Цель, видимо, указать, что это принципиально два разных типа: размер не может быть отрицательным, в отличии от смещения. E>>Зачем это указывать?
BFE>Для ясного понимания.
Для ясного понимания чего?
Вот зачем показывать, что число std::end( array ) — std::begin( array )
и число size( array ) -- это одинаковые значения разных типов?
BFE> Целое с плавающей точкой ? Это как?
Это так число из интервала [-1.0, 1.0]
E>>а для sizeof'а заводят таки специальный size_t?
BFE>видимо, чтобы не ограничивать возможность реализации "лишними" соглашениями
Этого совсем не понял. Так что там с разницой конца и начала массива? Она не обязана быть равна size, или что?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
BFE>>>>Цель, видимо, указать, что это принципиально два разных типа: размер не может быть отрицательным, в отличии от смещения. E>>>Зачем это указывать? BFE>>Для ясного понимания. E>Для ясного понимания чего? E>Вот зачем показывать, что число std::end( array ) — std::begin( array ) E>и число size( array ) -- это одинаковые значения разных типов?
Немного философии: бывают некоторые координаты в неком пространстве, пара координат задаёт вектор, длинна вектора неотрицательна...
Короче, разница двух индексов это не то же самое, что индекс. Разница двух индексов — это, по сути, вектор (так как важен порядок). А вот модуль этого вектора — длинна.
Индекс, разница двух индексов, модуль разности двух индексов — это три разных типа: итератор, difference_type, size_t.
BFE>> Целое с плавающей точкой ? Это как? E>Это так число из интервала [-1.0, 1.0]
Здравствуйте, Mystic, Вы писали:
А>>- Меня вот всегда удивляло, почему в качестве счетчика цикла, который будет использоваться в качестве индексации масива / контейнера, зачастую используется знаковая целочисленная переменная? А>>Нет, ну я понимаю, что size_t многим просто не нужен — пишу себе под 32 бита и буду писать, думают они.
M>Есть у size_t одна неприятность, когда это возвращаемое значение и нам надо вернуть еще признак ошибки. В случае знакового целого я верну -1 и не буду париться. Поэтому есть size_t, а есть ssize_t. А еще, бывает, надо из одного size_t вычесть другой, где отрицательный результат тоже имеет смысл.
У меня тут на днях, грубо говоря, неприятность случилась. Обнаружили, что там, где мы раньше просто передавали счётчик в 8 байтах, надо передавать ещё два значения — типа "ошибка снятия" и "отсутствие источника". Расширять некуда — грубо говоря, это embedded, протоколы и форматы в общем установлены. Но параметры не так быстро растут, чтобы переполнить 64 бита.
Так что выдвинул на внутреннее обсуждение предложение: "на ходу" сократить его до 63 бит, а случай старшего бита равного 1 применить на спец-значения. Вот жду до понедельника, будут ли фатальные возражения... По сути тут как раз и получилась замена беззнакового типа на знаковый.
Чувствую себя сотрудником Microsoft — согласно уровню извращений — заказчикам тоже придётся перестраиваться (хоть и не срочно).
M>Имхо, беззнакомый size_t это наследие 16-битных платформ, в частности DOS. Тут жертвуя старшим битом мы из 64k получаем 32k, что ощутимо неприятно. Уже на 32-битных платформах разница межу 2G и 4G не играет большой роли. Ситуация, когда надо именно 3G, но при этом заведомо меньше 4G, экзотична. А в случае 64-бит пожертвовать одним битом еще более не жалко. Отрицательные числа их же не зря ввели, они естественных образом получаются из целых.
Ну тогда давайте всё в плавучке считать, причём в комплексных. Они ведь тоже естественным образом получаются из целых, делить и брать корень — это ведь так естественно
А беззнаковость нужна, как минимум для действий, напрямую связанных с аппаратурой. Например, значение указателя — знаковое или таки без? Или вот длинная арифметика, она через какие значения реализуется?
(BTW, странно, что для поддержки длинной арифметики нет функции типа {a,b} -> {carry,sum} в стандартной библиотеке. В Verilog она есть.)
M>Беззнаковые хороши для битовый масок, когда операции сложения и вычитания используются только во всяких битовых хаках а-ля (x^(x-1)+1)>>1 при которых результат остается беззнаковым. Вообще, для таких случае рулят модульные типы Ada.
Я что-то не вижу, чем они "рулят". Они выглядят точно так же как сишные беззнаковые целые со всей их неуправляемостью.
Вот если бы Вы сказали про типы, для которых, например, 65535+1 генерировало бы исключение переполнения — тогда да, "рулят", потому что дают что-то новое по сравнению с текущей реализацией.
Сейчас, чтобы сделать такое эффективно, приходится придумывать аццкий бутерброд из ассемблера и C++.