#c #c #qt #casting #memcpy
#c #c #qt #Кастинг #memcpy
Вопрос:
У меня есть
QByteArray bytes // Fullfilled earlier
char id_c = bytes[7];
int _id;
_id = 0; // If I comment this result would be different
memcpy(amp;_id, amp;id_c, 1);
int result = _id;
У меня есть переменная _id, и если я прокомментирую переменную результата «_id = 0», результат будет отличаться с отрицательным числом. Почему? Почему инициализация _id с 0 будет отличаться ?!
Как я могу сделать это альтернативно с тем же результатом, что и при использовании «_id = 0», но без memcpy и нежелательных приведений?
Это не мой код. Мне интересно, как правильно получить тот же результат без глупых кастингов.
Комментарии:
1. вы копируете один байт на что-то, что (вероятно) составляет 4 байта. Если вы не инициализируете остальные 3 байта, вы получите мусор (технически неопределенное поведение). Есть ли причина, по которой вы не можете просто сделать
_id = id_c;
?2. Я бы попробовал это и сообщил, потому что я пытался, но забыл!
3. Результат зависит от последовательности. Хотя я полагаю, что переносимый код в любом случае невозможен, поскольку вы используете «кроссплатформенный» QT.
4. Планируете ли вы передавать / передавать данные по какой-либо сети?
bytes
5. Нет. Я бы не стал отправлять их через TX / RS. Я могу использовать пакеты QTcpSocket и ethernet
Ответ №1:
Правильно.
Потому что это утверждение:
memcpy(amp;_id, amp;id_c, 1);
Копирует только один байт из amp;id_c
в адрес, представляющий 4-байтовое целое число, amp;_id
. Только первый байт памяти, занятой, _id
получает что-либо скопированное в него. Без нулевого инициализации _id
first оставшиеся три байта этого значения остаются неопределенными (предположительно, случайные значения мусора из стека).
Что не так с «нежелательным приведением»? Это так же хорошо, и компилятор генерирует наиболее эффективный код.
QByteArray bytes // Fullfilled earlier
int _id = (int)(bytes[7]);
int result = _id;
Если вы хотите подписать расширенный результат скопированного беззнакового байта _id
, то это:
int _id = (signed char)(bytes[7]);
Комментарии:
1. это лучше, чем _id=0; _id = id_c? Почему это самый эффективный код?
2. Действительно сложно превзойти оптимизацию компилятора для присвоения значений между переменными.
memcpy
лучше всего подходит для массового копирования и выполнения некоторых очень эзотерических действий между адресами в памяти.3. Также
memcpy
полезен для очень явных операций сериализации из объектов (структур) в байтовые массивы и из них. Итак, это может быть полезно, если вы делаете что-то сложное, например, инициализируете структуру из массива байтов. Вы моглиmemcpy
бы перевести каждый отдельный элемент структуры в / из его ожидаемой позиции в массиве байтов. Но в приведенном выше примере вы имели дело всего с одним байтом, поэтому это становится намного более простой проблемой.
Ответ №2:
_id = 0
вызывается присвоением 0
значения переменной _id
, если вы прокомментируете это, тогда мы не можем быть уверены, что в ней хранится _id
, и вы обновляете только один байт из этого, поскольку он имеет тип int
, размер которого превышает один байт.
Комментарии:
1. Это объясняет причину проблемы, но на самом деле не отвечает на вопрос OP.
2. Я использовал _id = static_cast<int>(байты [7]), и это было неправильно. Я получаю код так, как он есть, и, полагаю, мой вопрос не точен
Ответ №3:
Вы можете попробовать эти преобразования порядка байтов сети / хоста:
единственное отличие заключается в используемом файле заголовка; Вы можете использовать приемы препроцессора для определения платформы и выбора правильного заголовка, если предполагается кроссплатформенное программирование. Лучшим подходом является использование функции C 20 std::endian
. Но вам нужно обработать преобразование самостоятельно:
#include <bit>
#include <climits>
int int_cvt(int x){
if constexpr (endian::native==endian::big)
return x;
y=0;
while(x){
unsigned char c=x;
x>>=std::CHAR_BIT;
y<<=std::CHAR_BIT;
y =c;
};
return y;
};
приветствую,
FM.
Комментарии:
1. Спасибо! Но нет C 2020
2. поэтому вам необходимо включить соответствующий заголовок, зависящий от ОС.
3. Существует QT с VS2008 IDE и компилятором и подключенной базой данных firebird. Мне нужно время, чтобы восстановить все.
4. так что ссылка на Windows должна делать.