#c
#c
Вопрос:
Как можно было бы «разделить», то есть тип long long, так, чтобы первая его часть находилась в var типа long, а вторая часть также была в var типа long.
long long long_type = 0xaaaabbbbccccdddd;
и в первом int я хотел бы иметь первую половину (не имеет значения, с какой стороны) переменной long_type, а во втором var int — вторую половину.
Ответ №1:
Ваш вопрос неоднозначен. Это зависит от того, что вы подразумеваете под «разделением». Вы можете разделить представление значений вашего оригинала long long
или вы можете разделить объектное представление вашего long long
.
Если вы хотите разделить представление значения, то ваш вопрос еще более неоднозначен из-за того факта, что ваше исходное значение имеет знак. Как вы собираетесь разделить значение со знаком? Какого результата вы ожидаете? Подписано? Без знака? Часть высокого порядка подписана, часть низкого порядка без знака? Или что-то еще?
Для значения без знака это будет выглядеть следующим образом (при условии, что тип получателя long
имеет правильный размер для ваших целей)
unsigned long long long_type = ...;
unsigned long hi = long_type / ULONG_MAX;
unsigned long lo = long_type;
Если вы хотите разделить представление объекта, правильным способом сделать это было бы использовать memcpy
(в этом случае знаковость исходного значения не имеет значения)
long long long_type = ...;
unsigned long hi, lo;
memcpy(amp;lo, amp;long_type, sizeof lo);
memcpy(amp;hi, (char *) amp;long_type sizeof lo, sizeof hi);
В этом случае, конечно, какая часть на самом деле является младшей, а какая — старшей, будет зависеть от платформы.
Комментарии:
1. @Мы ничего не можем сделать: потому что, по-видимому, я пока единственный, кто действительно понимает весь масштаб проблемы.
2. достаточно справедливо, но я не имел в виду ничего плохого. Я просто пошутил. Спасибо за ваш ответ. Наиболее ценится.
Ответ №2:
Я бы рекомендовал использовать uint32_t и uint64_t или другие типы с фиксированной шириной.
Затем используйте битовые операции, чтобы разделить его следующим образом:
uint64_t long_type = smthng;
uint32_t high = (long_type amp; 0xFFFFFFFF00000000ULL) >> 32;
uint32_t low = long_type amp; 0xFFFFFFFF;
Комментарии:
1. Но он конкретно спрашивает о
long long
. Почему вы меняете вопрос, чтобы ваш ответ выглядел лучше?2. @Nawaz все в порядке, я могу заменить любой тип на любой, если я знаю метод.
3. @piotr хотя мне нравится «ваш» метод, глядя на ответ Наваза, я просто думаю, не является ли «его» ((CHAR_BIT) * sizeof(long)); «более переносимым» для 32. О чем ты думаешь?
4. @piotr: Если типы имеют правильные размеры, то обе
amp;
операции совершенно не нужны и только запутывают код.5. @Andrey да, теперь, когда я смотрю на это во второй раз, я понимаю, что ты имеешь в виду. Да, вы правы.
Ответ №3:
long a = long_type;
long b = (static_cast<unsigned long long>(long_type) >> 32);
Комментарии:
1. Потому что круглые скобки делают все лучше.
2. @TonyK: Потому что мне нравятся круглые скобки. Они делают вещи более понятными для меня.
3. УБ! Сдвиг вправо для подписанного типа является неопределенным поведением.
4. @piotr Нет, это не так. Если значение отрицательное, результаты определяются реализацией, но только если значение отрицательное. И на практике существует только два варианта: вставляются нулевые биты или вставляются единичные биты. С другой стороны, при присвоении a
long
, если значение не помещается в along
, результаты определяются реализацией и могут привести к сигналу, который, если его не перехватить, может привести к завершению программы.5. @piotr: на самом деле это сдвиги влево для подписанных типов, которые могут привести к неопределенному поведению (в основном это неопределенное, если вы не начинаете с неотрицательного значения и заканчиваете значением, которое достаточно мало, чтобы оставаться таким).