Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 5.00/7: Рейтинг темы: голосов - 7, средняя оценка - 5.00
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524

[c++] упростить конструкцию safe_cast, преобразование типов без потерь данных

10.06.2020, 23:22. Показов 2296. Ответов 28

Студворк — интернет-сервис помощи студентам
Всем привет!

Сборка проекта на максимальных уровнях предупреждений очень часто терпит неудачу из-за предупреждений вида:
Code
1
error: conversion to 'DWORD' {aka 'long unsigned int'} from 'int' may change the sign of the result [-Werror=sign-conversion]

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

А на случай нарушения этого джентельменского соглашения хочется иметь дополнительную страховку.

Следующий код иллюстрирует сабж:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <type_traits>
#include <stdexcept>
#include <iostream>
#include <limits>
 
template<class ret, class from>
ret safe_cast(from&& val)
{
    using x = decltype( ::std::numeric_limits<ret>::max() );
    using y = ::std::remove_reference_t<from>;
    using z = ::std::common_type_t<x, y>;
    const auto& check = static_cast<z>(val);
    if(::std::numeric_limits<ret>::max() < check)
        throw ::std::logic_error("data loss conversion");
    return static_cast<ret>(val);
}
 
 
int main()
{
    try
    {
        size_t val = size_t(-10);
 
        int v = safe_cast<int>(val);
 
        std::cout << "v = " << v << '\n';
    }
    catch(const ::std::exception& e)
    {
        std::cerr << e.what() << '\n';
    }
}
Этот способ работает, но не мне нравится зависимость от limits
Не нравится зависимость от type_traits и decltype

Мне кажется можно сделать как то попроще.
Как то такие вещи же делали во времена с++03, когда decltype ещё не существовало?
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
10.06.2020, 23:22
Ответы с готовыми решениями:

Как работает safe_cast и чем отличается от обычного приведения типов?
Объясните пожалуйста как работает операция safe_cast. Максимально подробно, именно на низком уровне. То что на msdn-не хватает. ...

Сжатие целочисленных данных без потерь
Нужно сжать массив/вектор int16_t. Нужен быстрый алгоритм сжатия, т.к. такой массив поступает примерно раз в секунду. Поэтому алгоритм...

Переход между формами без потерь данных в текстбоксах
есть три формы нужно, чтобы при переходе между ними данные в текстбоксе оставались. У меня получается через раз... Код первой формы...

28
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,405
11.06.2020, 16:50
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от eva2326 Посмотреть сообщение
Задача заключается в том, что бы избавиться от предупреждений.
Предупреждения - компиляторно- зависимое свойство. "Избавиться от предупреждений" можно только задавив их компиляторно-зависимыми средствами, как на уровне кода, так и на уровне настроек компилятора.

Цитата Сообщение от eva2326 Посмотреть сообщение
Здесь написано, что касты int32_t <=> uint32_t совершенно безопасны.
Так как размер у типов одинаковый, то содержимое памяти при касте останется неизменным.
Ым.. Касты в С++ ни имеют никакого отношения к "содержимому памяти". Касты в С++ всегда работают только на уровне высокоуровневых/логических представлений значения. "Содержимое памяти" тут вообще впрямую не фигурирует.

Если вас интересует "содержимое памяти", то вам нужна реинтерпретация, а не касты. Реинтерпретацию делают memcpy, union и доcтуп через unsigned char * указатель.

Цитата Сообщение от eva2326 Посмотреть сообщение
Каст float <=> int32_t, при условии что sizeof(float) == 32 тоже безопасен?
В свете вышесказанного вами, это вопрос становится бессмысленным. О чем идет речь? О "содержимом памяти" (реинтерпретации) или все таки о касте (приведении типа)?

Цитата Сообщение от eva2326 Посмотреть сообщение
Проверку значения нужно делать только в случае, если кастим из объекта большего размера в объект меньшего размера?
Еще раз: тема кастов и потери (или не потери) информации при касте не имеет вообще никакого отношения к размерам объектов.

Цитата Сообщение от eva2326 Посмотреть сообщение
Но я имела ввиду с точки зрения реинтерпретации данных.
Ах, к реинтерпретации... К чему тогда здесь этот код, который вы привели в исходном сообщении и который к реинтерпретации не имеет даже отдаленного отношения?

С реинтерпретацией данных все просто: байтов хватает - значит данные поместятся. Сравните sizeof, сделайте memcpy - и готово. Однако помните, что может получиться trap representation. Т.е. пытаться работать с float значением, полученным путем реинтерпретации int значения - это дикий бред и феерическая чушь (и да, я помню про трюк из doom).

---

Перечитал ваше исходное сообщение. Вердикт: и по процитированному предупреждению компилятора, и по приведенному коду очень хорошо видно, что ни о какой "реинтерпретации" речи в вашем вопросе не идет. Ваш вопрос - именно о приведении типа, т.е. о кастах. Этот вопрос я закрыл дал в сообщении #3. Зачем вы сейчас бросились выдумывать какую-то "реинтерпретацию" - тему, к который ваш изначальный вопрос не имел никакого отношения - мне не ясно.
0
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
11.06.2020, 16:55  [ТС]
Можно ли записать double во float без потерь?

Первый эксперимент:
Берем float, и засовываем его в double.
А потом вытаскиваем обратно из double во float.
Если получившееся значения пренебрежительно равно исходному, значит данное значение float можно без потерь поместить в double

Для тестирования использовала фреймворк gtest

C++
1
2
3
4
5
6
7
TEST_COMPONENT(001)
{
    const float  f1 = 13.13f;
    const double d  = f1;
    const float  f2 = d;
    ASSERT_FLOAT_EQ(f1, f2);
}
Два дробных считаются равны, если их значения отличаются очень не значительно.
Подробности в исходном коде gtest.

Кликните здесь для просмотра всего текста

у них там UB, кстати, в классе FloatingPoint,
но всем пофигу.


Результат: float можно записать в double без потерь данных.

Второй экперимент:
Берем double, и засовываем его во float.
А потом вытаскиваем обратно.
Если получившееся значения слишком сильно разнятся, значит нельзя сохранить double во float, без потерь данных

C++
1
2
3
4
5
6
7
TEST_COMPONENT(002)
{
    const double d1 = 13.13;
    const float  f  = static_cast<float>(d1);
    const double d2 = f;
    ASSERT_DOUBLE_EQ(d1, d2);
}
Тест провалился.

Отладчик показывает:

Code
1
2
3
d1  13.130000000000001
d2  13.130000114440918
f   13.1300001
Каст из float в double приводит к возникновению артефактов.

То есть по сути, каст из float в double приводит к искажению данных.
Что на мой взгляд, ещё хуже чем потеря данных.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,405
11.06.2020, 17:11
Цитата Сообщение от eva2326 Посмотреть сообщение
Каст из float в double приводит к возникновению артефактов.
То есть по сути, каст из float в double приводит к искажению данных.
Написана какая-то ерунда.

Каст из double в float приводит к искажению значения. Что ожидаемо.

Каст из float в double никогда не приводит к потере значения, по крайней мере в IEEE754 представлениях.

Все искажения в ваших экспериментах возникли только при касте из double в float, а не наоборот.

Цитата Сообщение от eva2326 Посмотреть сообщение
искажению данных.
Что на мой взгляд, ещё хуже чем потеря данных.
Это где, интересно, вы проводите водораздел между "искажением" и "потерей"???
2
 Аватар для eva2326
1685 / 513 / 107
Регистрация: 17.05.2015
Сообщений: 1,524
11.06.2020, 17:29  [ТС]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
"Избавиться от предупреждений" можно только задавив их компиляторно-зависимыми средствами, как на уровне кода, так и на уровне настроек компилятора.
Нет, не только.
Ещё можно просто писать нормальный код, который не агрит компиляторы.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Если вас интересует "содержимое памяти", то вам нужна реинтерпретация, а не касты.
Меня интересуют данные, которые не должны испортиться.
И компиляторы, которые не должны кидать предупреждений.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Этот вопрос я закрыл дал в сообщении #3
Код, представленный в #3 делает не то, что нужно.
И к тому же, возбуждает у компиляторов предупреждение.

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

Вы отдаёте себе отчет в том, что запостили такой код в тему, которая посвящена тому, как можно избавиться от подобных предупреждений?

Не находите, что это немножко глупо?

В этой теме я вообще не буду рассматривать код, который агрит компиляторы.

Добавлено через 3 минуты
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Каст из double в float приводит к искажению значения.
Я это и хотела написать. Я перепутала ))))

Ну видно же по эксперименту?
Цитата Сообщение от eva2326 Посмотреть сообщение
const float  f  = static_cast<float>(d1)
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,405
11.06.2020, 17:45
Цитата Сообщение от eva2326 Посмотреть сообщение
Ещё можно просто писать нормальный код, который не агрит компиляторы.
Нет, конечно. Во-первых, "нормальный код", о которым вы говорите - это и есть методы подавления предупреждений на уровне исходного кода, о которых я говорил выше. И которые, разумеется, по определению компиляторно-зависимы.

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

Цитата Сообщение от eva2326 Посмотреть сообщение
Меня интересуют данные, которые не должны испортиться.
Это при том, что вы до сих пор не определились, что значит "данные испортились". И при каких манипуляциях они должны (или не должны) портиться. Вы начали с кастов, потом вдруг забыли про касты и переключились не реинретпретацию памяти, потом снова забыли про реинретпретацию памяти и переключились на "круговой каст".

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

Цитата Сообщение от eva2326 Посмотреть сообщение
Вы отдаёте себе отчет в том, что запостили такой код в тему, которая посвящена тому, как можно избавиться от подобных предупреждений?
Еще раз: вы пока что еще сами не определились, чему посвящена эта тема, как я объяснил выше. На данный момент, я знаю чему посвящена ваша тема лучше вас. Так понятнее?

Цитата Сообщение от eva2326 Посмотреть сообщение
В этой теме я вообще не буду рассматривать код, который агрит компиляторы.
Боюсь что наличие в лексиконе терминов вроде "агрит" также является существенным препятствием к пониманию.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
11.06.2020, 17:58
Цитата Сообщение от eva2326 Посмотреть сообщение
Если получившееся значения пренебрежительно равно исходному,
eva2326, это не о реинтерпретации. Это именно о преобразовании значения. А дальше вступает математика. Я не большой математик, но перевод вашего:
Цитата Сообщение от eva2326 Посмотреть сообщение
пренебрежительно равно
применительно к мантиссам разной битности (бог с ним с показателем - он целый и тут легко представить что double можно ограничить максимумом для float) приводит к ограничению для double состоящему в странном требовании:
биты не задействованные во флоат должны быть нулевыми.
Знак не учитываю и формат считаю семантически подобным.
Это учитывая факт двоичного представления - задача пикантная. Не уверен в том, что есть нетривиальный способ это проконтролировать. Хотя написать платформеннозависимую функцию выполняющую битовый анализ и возвращающую даже ошибку округления (или невозможность представления) впринципе возможно. Но это далеко от возможностей преобразования типов языка С++. Может и писал кто-то что-то подобное.
0
Вездепух
Эксперт CЭксперт С++
 Аватар для TheCalligrapher
13235 / 6867 / 1827
Регистрация: 18.10.2014
Сообщений: 17,405
11.06.2020, 17:58
del
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
11.06.2020, 20:15
Для конкретно плавающих типов можно lexical_cast из boost применить. Говорить о скорости тут вряд ли придётся.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9007 / 4708 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
12.06.2020, 09:42
Вот ещё материал, но он уже содержит пыль веков. Компиляторы стали умнее. Однако, почитать может быть интересно:
Андрей Александреску Современное проектирование на С++
гл.2.1. Статическая проверка диагностических утверждений.
Тут о безопасности статических преобразований. По сути, как было сказано, компилятор и сам не даст данным умереть спокойно (сужающий вариант), но если хочется расширенной диагностической информации в то время как сообщение компилятора не устраивает, можно написать свои шаблоны.
гл.2.7. Распознавание конвертируемости и наследования на этапе компиляции
Это о возможности преобразований типов иерархии (указателей вернее). Разумеется, всё относится ко времени компиляции и ни как не конкурирует с RTTI.
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
12.06.2020, 09:42

Преобразование типов без исчезания нуля
ребят помогите с проблемой ... есть у меня label в нем написано число 01101 я это число хочу преобразовать в инт что бы в дальнейшем...

Упростить конструкцию
Возможно сделать ли проще код? $.each($(''), function(index, vl){ $(this).on('click', function(elem) { atr =...

упростить конструкцию
for (int i = 0, c_c = computer_player, c_h = human_player, r; i &lt; human_player + computer_player; i++) { r = rand() % 2; string...

Упростить конструкцию
Изначально: 22,33,44,66,55 $arrr = array_flip(explode(',',$gl)); // Создаем массив, затем меняем кличи со значением unset($arrr);...

Как упростить конструкцию?
Добрый всем вечер. Подскажите как можно упростить/сократить такую конструкцию: label7.Text = Array_Res_Level.ToString(); ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
29
Ответ Создать тему
Новые блоги и статьи
Особенности gif сгенерированных в Си
russiannick 21.10.2026
Рассмотрим генерацию gif файлов, которые в Си имеют свои особенности. Gif представляет собой графический формат популярный в интернете. Посмотрим на палитру. Gif файл сгенерированный в си отличается. . .
FPS контроллер с анимированными Y-Bot и 3D-звуком miniaudio (Box3D, Recast, BehaviorTree.CPP, ozz-animation, ImGui, OpenGL и SDL3)
8Observer8 18.10.2026
Содержание блога | English Version Полное мультиплатформенное руководство по стартовому проекту с FPS-контроллером игрока, анимированными роботами Y-Bot с 4-слойным блендингом, 3D-физикой Box3D,. . .
Локальный http сервер
Argus19 17.10.2026
Локальный http сервер На работе, на двух локальных компьютерах круглосуточно работают программы опроса приборов с записью в книги Excel,которые раз в сутки записываются на сервер компании. Т. к. . . .
Копировать Windows на новый диск на UEFI
damix 17.10.2026
https:/ / uriesk. wordpress. com/ 2016/ 11/ 01/ move-window-10-to-ssd-on-a-uefi-dualboot-system-with-basic-linux-tools/ TL DR Вставляем диск, а старый подключаем через переходник, грузимся с лайва. . .
ИИ не может найти нужный язык в списке
Supersumestria 05.10.2026
Я ему даю вот такое изображение и прошу найти и подчеркнуть немецкий язык. Возвращает он вот это: https:/ / i. **********/ vqBWLe2. png Нужную строчку в 3й колонке просто выдумал. . Это. . .
Новая последняя моя музыка в SUNO
zorxor 05.10.2026
Здравствуйте, дорогие мои друзья! С большой радостью я хотел бы представить вам свою новую последнею музыку, которую сгенерировала мне по моей просьбе нейросеть SUNO. С уважением, zorxor. Это. . .
Программный домашний кинотеатр
russiannick 27.09.2026
Сподобился на программный домашний кинотеатр. В качестве ЯВУ по традиции выбрал js. В помощники взял Яндекс-Алису. Было создано три зала на разные интересы. исторические и ретро сериал Хичкок. . .
Беседа с ИИ о программистах, недопускающих к созданию и правке кода генеративные ИИ и причины этого
zorxor 21.09.2026
Раньше я радовался или получал некоторые эмоции, пусть небольшие, но всё же, от самого процесса написания кода, рекомпиляции и запуска, видя постепенное развитие программы и прочее. А теперь лень. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru