Страница 223 из 386

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 19:31:20
vash_sa
Подскажите, пожалуйста, как из массива uint16_t получить массив uint8_t. Наоборот знаю. Необходимо, чтобы значения переменных не были искажены.
Спасибо!

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 19:38:34
ARV
интересно, как без искажений вы впихнете в uint8_t значение, например, 2096, которое легко помещается в uint16_t?

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 19:44:02
vash_sa
Мне надо разделить байты в 2 байтовом числе. Как это сделать?

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 19:53:58
uldemir

Код: Выделить всё

low = input & 0x00FF;
high = (input >> 8) & 0x00FF;
подразумевается low, high - uint8, input uint16
или надо что-либо более адванснутое?

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 19:59:51
ARV
задача поставлена слишком туманно, вариантов море:

Код: Выделить всё

// первый вариант: получаем массив байтов из массива int-ов
uint16_t source_array[SIZE]; // исходный массив
uint8_t *dest_array = (void*)source_array; // объявляем указатель на байт

uint8_t tmp = dest_array[10]; // извлекаем 11-й байт из исходного массива

// второй вариант: переделываем массив, оставляя только младшие байты из исходного массива
uint8_t dest_array[SIZE]; // объявляем результирующий массив
// в цикле заполняем массив
for(uint8_t i=0; i<SIZE; i++)
   dest_array[i] = source_array[i];

// третий вариант - то же, что и второй, но берем старший байт
for(uint8_t i=0; i<SIZE; i++)
   dest_array[i] = source_array[i] >> 8;
ну и дальше в рамках фантазии аналогично...

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 20:01:08
ARV
uldemir писал(а):

Код: Выделить всё

low = input & 0x00FF;
high = (input >> 8) & 0x00FF;
подразумевается low, high - uint8, input uint16
или надо что-либо более адванснутое?
избыточно, хватило бы и просто

Код: Выделить всё

low = input;
high = input >> 8;

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 20:12:40
uldemir
перестраховался на случай, если вздумает 32-х битное подсунуть :))

Re: Вопросы по С/С++ (СИ)

Добавлено: Вс июл 12, 2015 20:48:31
vash_sa
Огромное спасибо!

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн июл 13, 2015 20:51:30
vash_sa
Помогите еще разок. Теперь есть массив из uint8_t первый байт младший, второй старший. Как наиболее эффективно сделать массив uitn16_t?

Спасибо!

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн июл 13, 2015 22:37:01
WiseLord

Код: Выделить всё

typedef union {
  uint8_t arr8[10];
  uint16_t arr16[5];
} myType;

int main() {
  myType x;
  uint16_t a;

  x.arr8[0] = 0x34;
  x.arr8[1] = 0x57;

  a = x.arr16[0]; // a присвоили значение 0x5734;
}
Все сдвиги и прочее берёт на себя компилятор. Память у массивов arr8 и arr16 общая.

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт июл 14, 2015 07:08:48
ARV
самый эффективный способ из массива байтов получить массив int-ов (при условии, что байты расположены в правильном порядке - младший-старший), это использовать указатель, я уже писал об этом:

Код: Выделить всё

uint8_t source[SIZE]; // исходный массив байтов
uint16_t *dest = (void*)source; // новый массив
работать с таким указателем точно так же, как с массивом: dest - будет число из пары байт исходного массива. не ошибитесь только с индексацией - в новом массиве будет в 2 раза меньше элементов...

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 07:25:22
vash_sa
Еще раз огромное спасибо!

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 09:12:07
menzoda
ARV писал(а):самый эффективный способ из массива байтов получить массив int-ов (при условии, что байты расположены в правильном порядке - младший-старший), это использовать указатель
Не не не. А как же выравнивание адресов? Некоторые архитектуры могут работать только с данными, выровненными по адресу, кратному размеру данных (или большей степени двойки). То есть, чтобы прочитать/записать в int16, это значение должно располагаться в памяти по адресу, кратному хотя бы двум, если нужно прочитать/записать int32, то оно должно располагаться по адресу, кратному хотя бы четырем, и так далее.

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

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 09:37:22
ARV
menzoda писал(а):
ARV писал(а):самый эффективный способ из массива байтов получить массив int-ов (при условии, что байты расположены в правильном порядке - младший-старший), это использовать указатель
Не не не.
да да да :) поскольку речь идет об AVR, то рассуждения о выравнивании - это притянуто за уши. и порядок байтов в int тоже. о какой переносимости может идти речь, если embedded-avr-программы на 90% состоят из аппаратно-зависимых (т.е. по определению непереносимых) действий?!

теория - это сила, но совать ее бесконтрольно в практику - только мешать :)))

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 09:41:30
ks0
Да и на 32-битных не приведет к ошибке, выравнивание, не выравнивание, это забота компилятора. Сказали второй байт, значит второй байт.

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 10:00:46
menzoda
ks0 писал(а):это забота компилятора. Сказали второй байт, значит второй байт.
Компилятор конечно может обернуть работу с невыравненными данными в несколько дополнительных команд, но тогда мы заметно потеряем в производительности. Вот только я не уверен, что он обязан это делать, нужно читать стандарт и документацию на конкретный компилятор. Скорее всего в стандарте как всегда будет undefined behavior или implementation defined. Так что все-равно нужно включать голову и писать переносимый код.
ARV писал(а):о какой переносимости может идти речь, если embedded-avr-программы на 90% состоят из аппаратно-зависимых (т.е. по определению непереносимых) действий?!
А почему у меня программы не состоят на 90% из аппаратно-зависимых действий? Просто нужно минимизировать и отделять аппаратно-зависимый код от всего остального, и не плодить костыли да хаки там, где это не нужно. А это как раз тот случай, где их можно избежать.

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 10:04:18
ARV
menzoda писал(а):А почему у меня программы не состоят на 90% из аппаратно-зависимых действий?
я не виноват, что вам не повезло... :dont_know:
:)))
90% avr-овских проектов - это дрыгоножество и настройка периферии. если ваши проекты считают разложения Лагранжа - там будет 99% переносимого кода...

в сущности, спор бесполезен, истина где-то рядом...

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср июл 15, 2015 18:41:21
ks0
menzoda писал(а):Компилятор конечно может обернуть работу с невыравненными данными в несколько дополнительных команд, но тогда мы заметно потеряем в производительности. Вот только я не уверен, что он обязан это делать, нужно читать стандарт и документацию на конкретный компилятор. Скорее всего в стандарте как всегда будет undefined behavior или implementation defined.
Прикольно, представил себе почти все функции обработки строк char* оказываются undefined behavior!

Re: Вопросы по С/С++ (СИ)

Добавлено: Чт июл 16, 2015 19:40:17
ks0
Че-то у меня лыжи не едут при попытки хранить строки во флеш. AVR GCC, пишу так

Код: Выделить всё

#include <avr/io.h>
#include <avr/pgmspace.h>
const char* s PROGMEM = "Text";
void main()
{
	char c[20]; // буфер
	strcpy_P(c,s);
}
И вижу, что отладчик пишит, что во флеш по адресу 0х54 хранится число 0х60, которое есть указатель на адрес в ОЗУ, где и хранится сам текст, текст действительно там и оказывается. В буфер нефига вразумительного не копируется.
Че за фигня?! Т.е. во флеше только указатель, а сами данные в ОЗУ!

Re: Вопросы по С/С++ (СИ)

Добавлено: Чт июл 16, 2015 20:14:16
ARV
прочтите о том, как правильно размещать строки во флеш при использовании старых версий AVR GCC. вы допустили ошибку - вы разместили во флеш указатель, е строка у вас окажется в ОЗУ. зачем вам флешевый указатель на ОЗУ? правильно так:

Код: Выделить всё

PROGMEM char str[] = "Что-то там";
sprcpy_P(s, str);
Однако, во множестве случаев может быть гораздо удобнее использование макроса PSTR:

Код: Выделить всё

strcpy_P(s, PSTR("Что-то там"));
то есть можно задавать константные строки в таком виде, если более не потребуются адреса этих строк.

однако, в настоящее время WinAVR уже можно считать устаревшим компилятором, более свежие версии AVR GCC, а так же AVR Toolchain от Atmel уже поддерживают префикс __flash для определения констант в памяти программ, при этом работа с ними происходит прозрачно для большинства применений, т.е. уже не надо использовать функции с суффиксом _P или специальные средства типа pgm_read_byte