2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3, 4, 5  След.
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 19:57 
Заслуженный участник


02/08/11
7003
guryev в сообщении #1427858 писал(а):
Тут undefined behavior получится не из-за использования union, а из-за неизвестного порядка байтов, хотя автор об этом и не упоминает. Здесь можно только сказать, что выведется нулевой байт из u.x. Естественно, это может быть как символ 'x', так и 0.
То, о чём вы говорите, - это не undefined behavior. Вы говорите об implementation-defined behavior, когда может прочитаться не тот байт. А вам говорят об undefined behavior. Undefined behavior - это когда компилятор имеет право сгенерировать программу, форматирующую жёсткий диск, из-за нарушения программистом контракта. Запись в один член union и чтение из другого - это именно undefined behavior безотносительно порядка байтов, размера типов членов union и вообще чего бы-то ни было.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 20:10 
Заслуженный участник


27/04/09
28128
Может быть ещё guryev надеется, что стандарт не могли написать так, что от этого будет UB. На что я бы сказал, что эта надежда не очень обоснована, потому что по-моему изначально union был введён в C (а в плюсы-то унаследован потом) лишь ради возможности хранить одно из альтернативных полей, но не ради конверсии их значений друг в друга, а это вышло уже побочным эффектом, который, как впрочем и union целиком, в современном C++ уже не нужен (для изначального применения есть теперь std::variant, для второго выше уже показали reinterpret_cast.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 20:49 
Заслуженный участник


02/08/11
7003
arseniiv в сообщении #1427881 писал(а):
для второго выше уже показали reinterpret_cast
Лучше всё-таки bit_cast. (Обсуждалось где в одной из соседних тем.)

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 20:53 
Заслуженный участник


27/04/09
28128
Только за; мне самому тоже не стоит советовать насчёт языка, на котором не пишу.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 21:29 


29/12/13
306
warlock66613 в сообщении #1427885 писал(а):
arseniiv в сообщении #1427881 писал(а):
для второго выше уже показали reinterpret_cast
Лучше всё-таки bit_cast. (Обсуждалось где в одной из соседних тем.)


Совсем новенькое, из с++20 . У меня ни в майкрософтском cl 19.23.28106.4 , ни в gcc version 9.1.1, оно не заработало.(со стандартными библиотеками).
И если я правильно понял эту таблицу, то ни один компилятор эту возможность не поддерживает.(в своих стандартных библиотеках)

Скажите, а у вас как, где и в каком виде оно используется и работает(компилируется)?

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение26.11.2019, 21:35 
Заслуженный участник


02/08/11
7003
Seman в сообщении #1427891 писал(а):
Скажите, а у вас как, где и в каком виде оно используется и работает(компилируется)?
В виде копипаста, например, из https://github.com/v8/v8/blob/master/src/base/macros.h:
Цитата:
Используется синтаксис C++
template <class Dest, class Source>
V8_INLINE Dest bit_cast(Source const& source) {
  static_assert(sizeof(Dest) == sizeof(Source),
                "source and dest must be same size");
  Dest dest;
  memcpy(&dest, &source, sizeof(dest));
  return dest;
}

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 00:00 
Заслуженный участник


20/08/14
11780
Россия, Москва
warlock66613
Подскажите, а насколько гарантируется что этот самый memcpy реально не будет ничего делать? А то для long обычно конечно плевать (хотя могут быть исключения и тут), но вот для структур не влезающих дважды в память (или просто размером в гигабайты) это критично.

Упс, походу вопрос глупый, там же выделение нового объекта и копирование, я то думал просто смена типа указателя ... :facepalm: Тогда это вообще не решает исходную задачу, ведь изменение исходного объекта не будет отражено в новом, аналогично и наоборот, т.е. объекты никак не связаны после вызова возврата из bit_cast.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 00:33 


29/12/13
306
warlock66613 в сообщении #1427893 писал(а):
В виде копипаста,


Вобщем, понятно, сводится к "пока обернуть memcpy и ждать пока появится стандартный bit_cast", что вполне обосновано в случае проектов вроде v8.

Замечу, что процитированный мной пример из C.183(это правило из стандартных рекомендаций от 16 июня сего года, где редактор сам Страуструп.)
Полагаю, что если они рекомендуют использовать reinterpret_cast в подобных случаях, то наверное не просто так.
При этом, вроде как понятно, что не надо так делать вообще.
Цитата:
Accessing the result of an reinterpret_cast to a different type from the objects declared type is defined behavior (even though reinterpret_cast is discouraged), but at least we can see that something tricky is going on.
Реально, для каких целей вынимать байты из long/int ?
Там есть рекомендации по безопасности типов вроде
Цитата:
Type safety profile summary:
Type.1: Avoid casts: a. Don’t use reinterpret_cast; A strict version of Avoid casts and prefer named casts. b. Don’t use static_cast for arithmetic types; A strict version of Avoid casts and prefer named casts. c. Don’t cast between pointer types where the source type and the target type are the same; A strict version of Avoid casts. d. Don’t cast between pointer types when the conversion could be implicit; A strict version of Avoid casts.
Type.2: Don’t use static_cast to downcast: Use dynamic_cast instead.
Type.3: Don’t use const_cast to cast away const (i.e., at all): Don’t cast away const.
Type.4: Don’t use C-style (T)expression or functional T(expression) casts: Prefer construction or named casts.
Type.5: Don’t use a variable before it has been initialized: always initialize.
Type.6: Always initialize a member variable: always initialize, possibly using default constructors or default member initializers.
Type.7: Avoid naked union: Use variant instead.
Type.8: Avoid varargs: Don’t use va_arg arguments.
http://isocpp.github.io/CppCoreGuidelin ... ty-profile
Avoid casts- отдельным правилом.
И там рекомендуются альтернативы:
Цитата:
Note
If you feel the need for a lot of casts, there may be a fundamental design problem.
....
Alternatives
Casts are widely (mis) used. Modern C++ has rules and constructs that eliminate the need for casts in many contexts, such as

Use templates
Use std::variant
Rely on the well-defined, safe, implicit conversions between pointer types



Про memcpy, там нет, но очевидно, что она не безопасна, оно ещё со времен С были стандартные советы её избегать, в С++ чтобы включить про неё в рекомендации(чтобы не использовали) давно поднимали вопрос, но есть случаи где она нужна.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 00:41 
Заслуженный участник


02/08/11
7003
Seman в сообщении #1427898 писал(а):
Полагаю, что если они рекомендуют использовать reinterpret_cast в подобных случаях, то наверное не просто так.
Для доступа к байтам reinterpret_cast можно использовать всегда без каких-либо проблем. Если же захотите uint64_t разбить на два uint32_t, появляются сложности.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 01:23 


29/12/13
306
warlock66613 в сообщении #1427899 писал(а):
Для доступа к байтам reinterpret_cast можно использовать всегда без каких-либо проблем

В С++ можно разное делать, по разному. Очень много возможностей и мало ограничений(почти нет). Но не всё нужно всегда использовать и если есть лучший вариант или можно просто что-то не использовать, то можно и не использовать. Я хочу сказать, что можно reinterpret_cast и не использовать. Если можно избежать приводить типы из char в int, то наверное лучше избежать.

warlock66613 в сообщении #1427899 писал(а):
сли же захотите uint64_t разбить на два uint32_t, появляются сложности.

1) Не понимаю зачем, я такое могу захотеть.
2) Не вижу сложностей
Используется синтаксис C++
#include <iostream>

using namespace std;

int main()
{
    uint64_t tt=0x500000005 ;
        auto tt1 = reinterpret_cast<uint32_t*>(&tt);
        std::cout << tt1[0] << std::endl;
        std::cout << tt1[1] << std::endl;
    return 0;
}

 

вывод:
Цитата:
5
5

https://onlinegdb.com/By46HXi2S

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 02:22 
Заслуженный участник
Аватара пользователя


16/07/14
9151
Цюрих
Seman в сообщении #1427898 писал(а):
Реально, для каких целей вынимать байты из long/int ?
Например если мы хотим послать что-то по сети / записать на диск без тщательного кодирования.
Seman в сообщении #1427900 писал(а):
Не вижу сложностей
Потому что это UB. И если добавить запись, то не работает не только в теории, но и на практике https://onlinegdb.com/r1Rab4i3B
Используется синтаксис C++
#include <iostream>

int64_t f(int32_t *i32, int64_t *i64 ) {
  *i64 = 1;
  *i32 = 2;
  return *i64;
}

int main() {
  int64_t x = 0;
  std::cout << x << std::endl;
  x = f(reinterpret_cast<int32_t*>(&x), &x );
  std::cout << x << std::endl;
  return 0;
}


 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 03:00 


29/12/13
306
mihaild в сообщении #1427902 писал(а):
Например если мы хотим послать что-то по сети / записать на диск без тщательного кодирования.
И зачем для этого вынимать байты из long/int ? Почему не использовать буфер какой из std::byte или даже std::vector<std::byte> ?


mihaild в сообщении #1427902 писал(а):
Потому что это UB. И если добавить запись, то не работает не только в теории, но и на практике https://onlinegdb.com/r1Rab4i3B

Так да, но это абсолютно надуманная ситуация. С memcpy получить нерабочую(/и/или некорректно) программу ещё проще. И вообще с любыми указателями тоже. Поэтому не рекомендуется использовать ни то, ни другое.
И reinterpret_cast, тут особо нипричем. Тоже самое без него:
код: [ скачать ] [ спрятать ]
Используется синтаксис C++
#include <iostream>

int64_t f(int32_t *i32, int64_t *i64 ) {
  *i64 = 1;
  *i32 = 2;
  return *i64;
}

int main() {
  int64_t x = 0;
  std::cout << x << std::endl;
  int32_t *i32_0 = (int32_t*)&x ;
  x = f(i32_0, &x );
  std::cout << x << std::endl;
  return 0;
}
 

Вывод:
Цитата:
0
2

https://onlinegdb.com/Hy-_2Vinr

-- 27.11.2019, 03:05 --

upd.
mihaild в сообщении #1427902 писал(а):
код
0
1


Полагал, что
Цитата:

0
2
т.к. (и ваш и мой код именно это и выдает, что разумеется "не ожидаемо") и
Цитата:

0
1
-- это верно(ожидаемо).

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 09:18 


27/02/09
253
Seman в сообщении #1427863 писал(а):
Поясните, пожалуйста, чем отличается:
Используется синтаксис C++
u.c[0]
от вашего
Используется синтаксис C++
char_values[idx]

Ничем. Я же говорю, что дело не в обращении к u.c[0], а в том, как это применяется:
Используется синтаксис C++
void bad(Pun& u)
{
    u.x = 'x';
    cout << u.c[0] << '\n';       // undefined behavior (1)
}
 
Здесь в little-endian архитектуре выведется 'x', а в big-endian - нулевой байт.
Seman в сообщении #1427863 писал(а):
Что будет, если значение в idx больше размера long ?
Что будет, если обратиться к 1230-му элементу четырёхэлементного массива? При чём здесь это? Вы исходное сообщение читали?

Вообще, хотелось бы напомнить: что использование union в данной задаче, что использование преобразованного указателя, напр. после reinterpret_cast - всё это формально относится к Undefined Behavior. Просто в данном случае это безопасно, только и всего.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 09:41 
Заслуженный участник


02/08/11
7003
Seman в сообщении #1427905 писал(а):
И зачем для этого вынимать байты из long/int ?
Затем, что мы хотим послать по сети этот long/int.
Seman в сообщении #1427905 писал(а):
Тоже самое без него
Это не "без него". Это с ним же, только записанным неявно, в виде old-fashion cast. Так делать в C++ вообще не нужно никогда.
Seman в сообщении #1427905 писал(а):
Так да, но это абсолютно надуманная ситуация.
В вашем исходном коде уже UB. Просто это не так очевидно.
guryev в сообщении #1427914 писал(а):
использование преобразованного указателя, напр. после reinterpret_cast - всё это формально относится к Undefined Behavior
Это ложь. А вот с union - да.
guryev в сообщении #1427914 писал(а):
Просто в данном случае это безопасно, только и всего.
Вам надо разобраться что такое UB.

 Профиль  
                  
 
 Re: c++ задача на битовые операции
Сообщение27.11.2019, 09:46 


27/02/09
253
warlock66613 в сообщении #1427916 писал(а):
Это ложь. А вот с union - да.
Правильно, воздержитесь от лжи.
Цитата:
Examples of undefined behavior are ... access to an object through a pointer of a different type, etc.
- https://en.cppreference.com/w/cpp/language/ub

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 68 ]  На страницу Пред.  1, 2, 3, 4, 5  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group