реклама на сайте
подробности

 
 
3 страниц V   1 2 3 >  
Closed TopicStart new topic
> Что означает этот код?
RW6MKA
сообщение Mar 8 2014, 15:05
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Здравствуйте уважаемые форумчане. Возник вопрос при оптимизации кода. Было
Код

                data[0] = w1_receive_byte();//читаем два байта с температурой
        data[1] = w1_receive_byte();
            //загоняем в двух байтную переменную
        temp = data[1];
        temp = temp<<8;
        temp |= data[0];

Подсказали что лучше использовать такое выражение
Код
        *((char *)&Temp;) = w1_receive_byte();
        *((char *)&Temp; + 1) = w1_receive_byte();

Вот никак не могу понять смысла этого кода. Я так понимаю что * и & это операции над указателями , а () приведение к типу но....
Вообщем если не трудно объясните начинающему подробно смысл сей конструкции.
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 8 2014, 15:15
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(RW6MKA @ Mar 8 2014, 19:05) *
Код
        *((char *)&Temp;) = w1_receive_byte();
        *((char *)&Temp; + 1) = w1_receive_byte();

Вот никак не могу понять смысла этого кода. Я так понимаю что * и & это операции над указателями , а () приведение к типу но....

У вас этот код компилируется? Врядли...Точки с запятой лишние.

Код
unsigned short Temp;
        *((char *)&Temp) = w1_receive_byte();
        *((char *)&Temp + 1) = w1_receive_byte();

Смысл такой - берётся адрес Temp и в него пишется 1 байт.Во второй строчке - пишется ещё байт по адресу следующего байта.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 8 2014, 15:29
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



А более подробно можно. Конкретно по каждому знаку. Просто общий смысл как бы я сразу понял ( из того что предложили сделать замену, значит этот код выполняет ту же функцию). Хотелось бы полностью понимать, что бы в последствии не было проблем с использованием подобных конструкций.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 8 2014, 15:36
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(RW6MKA @ Mar 8 2014, 19:05) *
Подсказали что лучше использовать такое выражение

А чем лучше - не подсказали? А на деле оно хуже.

Цитата(RW6MKA @ Mar 8 2014, 19:29) *
А более подробно можно. Конкретно по каждому знаку.

&Temp - взяли адрес Temp
(char *)&Temp - привели к типу указателя на char
*((char *)&Temp) = w1_receive_byte() - по указателю на char, который равен адресу Temp, занесли результат w1_receive_byte().
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 8 2014, 15:37
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(RW6MKA @ Mar 8 2014, 19:29) *
А более подробно можно

Берётся адрес Temp: &Temp
приводится к указателю на char: (char *)(полученный адрес)
по указателю на char делается запись того что вернёт функция:
*(указатель на char)=w1_();

Со второй строчкой также - только ещё инкремент указателя есть.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 8 2014, 15:54
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Ну вроде экономия памяти при компиляции. Можно конечно оставить и свой код, места мне хватает, но задело, не сталкивался с подобным и поэтому хочу понять. Народ, не сочтите за труд, поэтапно объясните. &Temp - выдаст адрес переменной. (char*)&Temp - приведение типа адреса переменной Temp к типу char(не пойму зачем знак *) и наконец зачем знак * в самом начале выражения?

Цитата(aaarrr @ Mar 8 2014, 19:36) *
А чем лучше - не подсказали? А на деле оно хуже.


&Temp - взяли адрес Temp
(char *)&Temp - привели к типу указателя на char
*((char *)&Temp) = w1_receive_byte() - по указателю на char, который равен адресу Temp, занесли результат w1_receive_byte().

Ага, понял. А в следующем выражении заносят по адресу Temp+1. то есть получаем эти два байта записанные в соседних адресах или я что то путаю?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 8 2014, 15:57
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



* - указатель

Без лишней памяти лучше будет написать так:
Код
temp = (char)w1_receive_byte();
temp = (temp << 8) | (char)w1_receive_byte();

(char) нужны только на случай, если w1_receive_byte() возвращает что-то другое.

Вариант
Код
*((char *)&Temp) = w1_receive_byte();
*((char *)&Temp + 1) = w1_receive_byte();

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

Цитата(RW6MKA @ Mar 8 2014, 19:54) *
Ага, понял. А в следующем выражении заносят по адресу Temp+1. то есть получаем эти два байта записанные в соседних адресах или я что то путаю?

Да, так.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 8 2014, 15:58
Сообщение #8


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(_Артём_ @ Mar 8 2014, 19:37) *
Берётся адрес Temp: &Temp
приводится к указателю на char: (char *)(полученный адрес)
по указателю на char делается запись того что вернёт функция:
*(указатель на char)=w1_();

Со второй строчкой также - только ещё инкремент указателя есть.

Вот этого не могу понять. Что это - приводиться к указателю? Приводится к типу понятно, а это выражение не пойму.
Go to the top of the page
 
+Quote Post
Harvester
сообщение Mar 8 2014, 16:01
Сообщение #9


Местный
***

Группа: Участник
Сообщений: 338
Регистрация: 1-02-06
Из: Королев, М.О.
Пользователь №: 13 846



Ужас какой-то. Это как раз тот случай, когда достоинства языка превращают в недостатки кода sm.gif
Вполне достаточно такого кода, все понятно и ничего лишнего:
Код
temp = w1_receive_byte();
temp <<= 8;
temp |= w1_receive_byte();

Хотя, если data[] - локальная переменная и больше нигде не используется, компилятор ее сам выкинет.


--------------------
-Да как так-то?/-Да как-то так/-Ну так-то да
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 8 2014, 16:02
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(RW6MKA @ Mar 8 2014, 19:58) *
Вот этого не могу понять. Что это - приводиться к указателю? Приводится к типу понятно, а это выражение не пойму.

Есть тип char, есть тип "указатель на char" - вот к последнему и приводится.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 8 2014, 16:13
Сообщение #11


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(aaarrr @ Mar 8 2014, 20:02) *
Есть тип char, есть тип "указатель на char" - вот к последнему и приводится.

Да, здесь в моих знаниях пробел.(( Спасибо всем за столь подробные объяснения. Чувствую, мне еще учить и учить))))
Еще раз всем спасибо.
Go to the top of the page
 
+Quote Post
Harvester
сообщение Mar 8 2014, 16:25
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 338
Регистрация: 1-02-06
Из: Королев, М.О.
Пользователь №: 13 846



Цитата(RW6MKA @ Mar 8 2014, 19:58) *
Вот этого не могу понять. Что это - приводиться к указателю? Приводится к типу понятно, а это выражение не пойму.

Указатель - это просто переменная, хранящая адрес в памяти.
Temp - 2-байтная переменная. Если указатель на Temp равен A, то содержимое переменной лежит по адресам [A] и [A+1]. Если мы просто инкрементируем указатель, он станет равным A+2, т.е. будет указывать на следующую 2-байтную переменную. А поскольку нам надо писать "внутрь" переменной, мы приводим тип к указателю на char. Тем самым говорим компилятору, что при инкременте указателя, его значение нужно увеличить не на 2, а на 1. Это позволит нам выполнить запись по адресу [A+1].


--------------------
-Да как так-то?/-Да как-то так/-Ну так-то да
Go to the top of the page
 
+Quote Post
SSerge
сообщение Mar 8 2014, 16:33
Сообщение #13


Профессионал
*****

Группа: Свой
Сообщений: 1 719
Регистрация: 13-09-05
Из: Novosibirsk
Пользователь №: 8 528



Цитата(Harvester @ Mar 8 2014, 23:01) *
Ужас какой-то. Это как раз тот случай, когда достоинства языка превращают в недостатки кода sm.gif
Вполне достаточно такого кода, все понятно и ничего лишнего:
Код
temp = w1_receive_byte();
temp <<= 8;
temp |= w1_receive_byte();

Немного позанудствую.
С первой и второй строкой всё нормально, а вот с третьей...
Результат выполнения этого может быть разным в зависимости от типов данных переменной temp и типа, возвращаемого функцией w1_receive_byte(). Даже если он определён как char, это ещё ничего не гарантирует, в С char может быть как знаковым так и беззнаковым, отдано на откуп реализации.
Для конкретного компилятора может и прокатит, как правило сейчас char считается беззнаковым.
Но если заботиться о переносимости, то надёжнее явно привести к беззнаковому типу:

temp |= (unsigned char)w1_receive_byte();

или, ещё лучше и короче c использованием типов из stdint.h :
temp |= (uint8_t)w1_receive_byte();


--------------------
Russia est omnis divisa in partes octo.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 03:47
Сообщение #14


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(Harvester @ Mar 8 2014, 20:25) *
Указатель - это просто переменная, хранящая адрес в памяти.
Temp - 2-байтная переменная. Если указатель на Temp равен A, то содержимое переменной лежит по адресам [A] и [A+1]. Если мы просто инкрементируем указатель, он станет равным A+2, т.е. будет указывать на следующую 2-байтную переменную. А поскольку нам надо писать "внутрь" переменной, мы приводим тип к указателю на char. Тем самым говорим компилятору, что при инкременте указателя, его значение нужно увеличить не на 2, а на 1. Это позволит нам выполнить запись по адресу [A+1].

То есть если бы мы сделали вот так
Код
((char)&Temp) = w1_receive_byte();//здесь просто адрес переменной привели к типу char и производим по нему запись т.к. переменная двух байтовая то адрес занимает грубо две ячейки и мы одну из них заняли.
((char)&Temp + 1) = w1_receive_byte();//в этой строке следующий адрес переменной приводим к типу char производим по нему запись, но запись получается уже по другим двум ячейкам.

в результате получаем запись двух байтов по двум разным адресам переменной.
А если приводить не к типу, а указателю на тип
Код
(char*)&Temp
и производить запись в указатель всего этого безобразия
Код
*((char*)&Temp)
, то мы записываем данные по, скажем, первой ячейке адреса, предназначенной для младшего байта, а при
Код
*((char*)&Temp+1)
по второй ячейке этого же адреса, предназначенной для старшего байта.
Я на правильном пути?
И ещё попутный вопрос. Правильно ли я выбрал тип переменной char если переменная это дробные числа имеющие разный знак? Может лучше использовать тип float?
вот функция целиком
Код
char temp_18b20(){//функция преобразует полученые с датчика 18b20 данные в температуру

    char temp = 0;
    if(TD_find()==1)//если устройство присутствует на шине
    {
        TD_sendcmd(0xcc);//пропустить ROM код, так ка датчик в устройстве один и не требуется идентификация
        TD_sendcmd(0x44);//команда датчику преобразовать температуру
        _delay_ms(750);//преобразование в 12 битном режиме занимает 750ms
        TD_find();//снова опрос присутствия и пропуск кода
        TD_sendcmd(0xcc);
        TD_sendcmd(0xbe);//команда датчику передать байты (у 18b20 в первых двух байтах содержится температура)
        //читаем два байта с температурой и записываем оба байта в двух байтовую переменную
        temp = (char)TD_receive_byte();
        temp = (temp << 8) | (char)TD_receive_byte();
        //переводим в градусы
        //пока кода нет, но в результате будут температурные данные
    }
    //возвращаем температуру
    return temp;
}
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 04:09
Сообщение #15


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(RW6MKA @ Mar 9 2014, 07:47) *
То есть если бы мы сделали вот так
Код
((char)&Temp) = w1_receive_byte();//здесь просто адрес переменной привели к типу char и производим по нему запись т.к. переменная двух байтовая то адрес занимает грубо две ячейки и мы одну из них заняли.
((char)&Temp + 1) = w1_receive_byte();//в этой строке следующий адрес переменной приводим к типу char производим по нему запись, но запись получается уже по другим двум ячейкам.

в результате получаем запись двух байтов по двум разным адресам переменной.

Некоторая каша получилась.
1. По приведенному к типу char адресу переменной записать ничего нельзя, это и не скомпилируется.
Это примерно как написать: 5 = 10;
2. Размерность адреса никак не связана с размерностью переменной.
Нужно понимать, что адрес, полученный через "&", является просто числом, а не новой переменной.

Цитата(RW6MKA @ Mar 9 2014, 07:47) *
А если приводить не к типу, а указателю на тип
Код
(char*)&Temp
и производить запись в указатель всего этого безобразия
Код
*((char*)&Temp)
, то мы записываем данные по, скажем, первой ячейке адреса, предназначенной для младшего байта, а при
Код
*((char*)&Temp+1)
по второй ячейке этого же адреса, предназначенной для старшего байта.
Я на правильном пути?

Ага, на правильном.

Цитата(RW6MKA @ Mar 9 2014, 07:47) *
И ещё попутный вопрос. Правильно ли я выбрал тип переменной char если переменная это дробные числа имеющие разный знак? Может лучше использовать тип float?
вот функция целиком
Код
char temp_18b20(){//функция преобразует полученые с датчика 18b20 данные в температуру
char temp = 0;
if(TD_find()==1)//если устройство присутствует на шине
{
    ...
    temp = (char)TD_receive_byte();
    temp = (temp << 8) | (char)TD_receive_byte();
    //переводим в градусы
    //пока кода нет, но в результате будут температурные данные
    ...
    //возвращаем температуру
    return temp;
}

Переменная temp должна иметь тип как минимум short, чтобы в нее поместилось два char'а.
Float имеет смысл использовать на более высоком уровне, например:
Код
short temp_18b20()
{
    ...
}

int main(void)
{
    float t;

    t = (float)temp_18b20() / 16;
    pritnf("Temp = %1.2f\n", t);
}
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 07:11
Сообщение #16


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(aaarrr @ Mar 9 2014, 08:09) *
По приведенному к типу char адресу переменной записать ничего нельзя, это и не скомпилируется.
Это примерно как написать: 5 = 10;

Понял. Да, мог бы конечно и сам понять что в адрес ничего не запишешь, можно записать по указателю адреса.
Цитата
Переменная temp должна иметь тип как минимум short, чтобы в нее поместилось два char'а.

Но short вроде бы тип для целых чисел, а у меня переменная Temp потом будет преобразовывать свое содержимое из двух байт двоичного кода в десятичные показания температуры с точностью до десятых. И сама функция будет возвращать такое число. Поэтому я и спросил за float, может лучше это тип использовать?

Сообщение отредактировал RW6MKA - Mar 9 2014, 07:12
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 07:30
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Обычно из таких - низкоуровневых - функций данные в плавающей точке все же не вытаскивают. Но если очень хочется, то можно.
Другой вопрос, нужен ли будет на деле этот float потом.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 08:20
Сообщение #18


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(aaarrr @ Mar 9 2014, 11:30) *
Обычно из таких - низкоуровневых - функций данные в плавающей точке все же не вытаскивают. Но если очень хочется, то можно.
Другой вопрос, нужен ли будет на деле этот float потом.

Хорошо, может это стрельба по воробьям из пушки. Какой тип вы для этой функции и переменной порекомендуете, если в результате функция должна вернуть число от -45,5 до 45,5 ?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 08:28
Сообщение #19


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(RW6MKA @ Mar 9 2014, 12:20) *
Какой тип вы для этой функции и переменной порекомендуете, если в результате функция должна вернуть число от -45,5 до 45,5 ?

Я бы оставил short, а привести/масштабировать всегда можно по месту.
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 08:32
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(RW6MKA @ Mar 9 2014, 12:20) *
от -45,5 до 45,5 ?


Умножте это дело на 10, получите -455...455, это влезает в 16 битное целое с запасом.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 08:56
Сообщение #21


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Во общем из советов я прихожу к выводу, что float лучше не использовать, а все постараться свести к типу целых чисел например int или short. Кстати вот еще вопрос, чем они отличаются? Как я понял и тот и тот тип могут быть 16 битным.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 09:13
Сообщение #22


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Могут. На 8-16 битных архитектурах ничем не отличаются. На архитектурах большей разрядности short может (по стандарту никто не обязывает) остаться 16 битным, а int соответствует разрядности процессора.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 09:35
Сообщение #23


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Понятно. Тогда с учетом того, что я пишу код в AVRStudio под tiny2313 будет ли правильной вот эта функция
Код
uint16_t temp_18b20(){//функция получает с датчика данные с температурой в виде двух байт

    uint16_t temp = 0;
    if(TD_find()==1)//если устройство присутствует на шине
    {
        TD_sendcmd(0xcc);//пропустить ROM код, так ка датчик в устройстве один и не требуется идентификация
        TD_sendcmd(0x44);//команда датчику преобразовать температуру
        _delay_ms(750);//преобразование в 12 битном режиме занимает 750ms
        TD_find();//снова посылаем Presence и Reset
        TD_sendcmd(0xcc);
        TD_sendcmd(0xbe);//команда датчику передать байты (у 18b20 в первых двух байтах содержится температура)
        //читаем два байта с температурой и записываем оба байта в двух байтную переменную
        temp = TD_receive_byte();
        temp = (temp << 8) | TD_receive_byte();
        
    }
    //возвращаем температуру
    return temp;
}
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 09:38
Сообщение #24


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Правильнее будет int16_t, а не uint - результат ведь знаковый. И проверьте, что TD_receive_byte() возвращает char, а не больше.
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 09:44
Сообщение #25


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(aaarrr @ Mar 9 2014, 13:38) *
Правильнее будет int16_t


Не совсем правильнее. Еще один момент есть - при таком раскладе, если Если TD_receive_byte() возвращаяет signed char, то операция temp = (temp << 8) | TD_receive_byte() убьет старший байт, если 7-ой бит там окажется в единице, и расширится до 16 бит. Так что, поосторожнее, надо бы на всяк случай написать temp = (temp << 8) | ((unsigned char)TD_receive_byte()). Вариант с прямой записью байтов на свои места по указателю в данном случае не имеет под собой таких "засад".
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 09:48
Сообщение #26


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(aaarrr @ Mar 9 2014, 13:38) *
Правильнее будет int16_t, а не uint - результат ведь знаковый. И проверьте, что TD_receive_byte() возвращает char, а не больше.

Нет, знак еще находится в коде, т.е. если 11-15 биты 1,то знак будет -. Так же и с дробной частью. Она заложена в 0-3 битах. Все это буду извлекать в отдельной функции с преобразованием в код LCD дисплея. Функция TD_receive_byte() возвращает uint8_t.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 10:06
Сообщение #27


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(RW6MKA @ Mar 9 2014, 13:48) *
Нет, знак еще находится в коде, т.е. если 11-15 биты 1,то знак будет -.

Это понятно. Но если Вы хотите, чтобы этот знак был учтен в дальнейшем, то результат должен быть знаковый:
short s = 0xffff;
unsigned short us = 0xffff;
float f;

f = s; // f = -1;
f = us; // f = 65535

Цитата(RW6MKA @ Mar 9 2014, 13:48) *
Функция TD_receive_byte() возвращает uint8_t.

Тогда порядок.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 10:15
Сообщение #28


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Цитата(aaarrr @ Mar 9 2014, 14:06) *
Но если Вы хотите, чтобы этот знак был учтен в дальнейшем, то результат должен быть знаковый:

Понятно. Учту.
Спасибо всем за подробные ответы. Надеюсь и в дальнейшем на вашу помощь.
Go to the top of the page
 
+Quote Post
Xenia
сообщение Mar 9 2014, 10:34
Сообщение #29


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



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

В этом плане выражение
Код
*(char *)&Temp = TD_receive_byte();
*((char *)&Temp + 1) = TD_receive_byte();
было вполне оптимальным, с тем лишь недостатком, что оказалось непонятным топикстартеру. Т.е. его и надо было просто разъяснить, но не возвращаться к сдвигу.

На этот счет могу предложить альтернативу с union, которая в максимальной степени оптимальна, но гораздо проще в понимании:
Код
uint16_t temp_18b20()
{
  union {
    unsigned char byte[2];
    uint16_t word;
  } temp;

  ...
  temp.byte[1] = TD_receive_byte();
  temp.byte[0] = TD_receive_byte();
   ...
  return temp.word;
}

Здесь union располагает в одной и той же памяти 2 байта byte и одно слово word, тем самым, позволяя заполнить последнее по частям.
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 10:41
Сообщение #30


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(Xenia @ Mar 9 2014, 14:34) *
т.е. стремления избавиться от операции 8-кратного сдвига, который МК обычно не умеют делать одной инструкцией.

Вот это, как раз, большинство 8-разрядных МК делают одной командой с легкостью, так как 16-битные регистры образуются из пар 8-битных, и такой сдвиг оптимизируется в пересылку сразу в нужный регистр.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 10:46
Сообщение #31


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Xenia @ Mar 9 2014, 14:34) *
Судя по стартовому посту темы, вопрос касался оптимизации кода, т.е. стремления избавиться от операции 8-кратного сдвига, который МК обычно не умеют делать одной инструкцией. А то и вызывают на этом месте библиотечную функцию, которая осуществялет сдвиги в цикле со счетчиком.

На 8? В 21-м веке? Со счетчиком? Не верю.


Цитата(Xenia @ Mar 9 2014, 14:34) *
Здесь union располагает в одной и той же памяти 2 байта byte и одно слово word, тем самым, позвояяя заполнить последнее по частям.

Во-первых, громоздко; во-вторых, что будем с эндианизьмом делать?
Go to the top of the page
 
+Quote Post
Xenia
сообщение Mar 9 2014, 10:49
Сообщение #32


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Цитата(SM @ Mar 9 2014, 14:41) *
Вот это, как раз, большинство 8-разрядных МК делают одной командой с легкостью, так как 16-битные регистры образуются из пар 8-битных, и такой сдвиг оптимизируется в пересылку сразу в нужный регистр.


Всё это лишь надежда на то, что компилятор при оптимизации исправит наш дурацкий код. sm.gif Но тогда зачем такой код писать? Тогда как через union оно так красиво записывается, что глаз не оторвать! sm.gif
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 9 2014, 10:50
Сообщение #33


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(aaarrr @ Mar 9 2014, 14:46) *
Во-первых, громоздко; во-вторых, что будем с эндианизьмом делать?

А что, большие индейцы разве не вымерли?
В 21 веке только мелкие как правило попадаются...Или нет?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 10:58
Сообщение #34


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(_Артём_ @ Mar 9 2014, 14:50) *
В 21 веке только мелкие как правило попадаются...Или нет?

У Вас есть роутер?
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 11:07
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(Xenia @ Mar 9 2014, 14:49) *
Но тогда зачем такой код писать?

Если переменная находится именно в памяти, а не проходит процесс обработки, и не возвращается функцией, то такой код вполне оправдан... А иначе - наоборот, вреден, так как вынудит компилятор сначала записать в память, а потом из нее взять в регистры.

PS
А union мне не нравится, не люблю лишние сущности. Напрямую оно понятнее, так как сразу все видно и понятно, без заглядывания в описание юниона. Главное язык программирования знать, чтобы не смотреть на эту запись, как ТС в начале темы.

PPS
А с эндианизьмом - #ifdef ....
Go to the top of the page
 
+Quote Post
_Артём_
сообщение Mar 9 2014, 11:08
Сообщение #36


Гуру
******

Группа: Свой
Сообщений: 2 128
Регистрация: 21-05-06
Пользователь №: 17 322



Цитата(aaarrr @ Mar 9 2014, 14:58) *
У Вас есть роутер?

Нет, у меня нет роутера. Что это такое? sm.gif
Вы намекаете, что MIPS имеет big endian? Не знал...
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 11:11
Сообщение #37


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(_Артём_ @ Mar 9 2014, 15:08) *
что MIPS имеет big endian? Не знал...


А еще многие имеют программируемый endian. Например TI C6000, да и АРМы тоже не все little, особенно из кортексов-А
Go to the top of the page
 
+Quote Post
adnega
сообщение Mar 9 2014, 11:21
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 2 724
Регистрация: 14-05-07
Из: Ярославль, Россия
Пользователь №: 27 702



Господа программисты, особенно начинающие, обратите серьезное внимание на решение от Ксении.
Хватит уже думать на уровне инструкций, переходите на уровень управления данными!
union и struct позволяют сделать код в разы "читабельней" и "управляемей".
Завтра вместо DS18B20 возьмете DS1820 и будете по всему коду искать сдвиги и прогие логические операции?!

Код
uint16_t temp_18b20()
{
  union {
    unsigned char byte[2];
        uint16_t  word;
      struct
       {
      uint16_t  ds18b20_f:4;
          uint16_t  ds18b20_i:8;
        };
        struct
        {
           uint16_t  ds1820_f:1;
           uint16_t  ds1820_i:8;
        };
        struct
        {
           uint16_t  ds_uni_f:N // ваше число бит для дробной части
           uint16_t  ds_uni_i:8; // целая часть температуры
        }
  } temp;

  ...
  temp.byte[1] = TD_receive_byte();
  temp.byte[0] = TD_receive_byte();
   ...
  return temp.ds_uni_i;
}


Меняете в одном месте N и все!
Go to the top of the page
 
+Quote Post
SM
сообщение Mar 9 2014, 11:26
Сообщение #39


Гуру
******

Группа: Свой
Сообщений: 7 946
Регистрация: 25-02-05
Из: Moscow, Russia
Пользователь №: 2 881



Цитата(adnega @ Mar 9 2014, 15:21) *
union и struct позволяют сделать код в разы "читабельней" и "управляемей".


Сильно поспорю. Читаемее то, для прочтения чего не надо искать хидер, где описан юнион, читать и разбирать этот хидер, и возвращаться к исходнику с использованием юнита (а без этого подумается, что тут просто запись в структуру, не юнион). Прямое средство запутывания следов. А прямая запись по указателю, как раз, сразу читается, без поиска концов по хидерам.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 11:30
Сообщение #40


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(SM @ Mar 9 2014, 15:26) *
Прямое средство запутывания следов.

Соглашусь полностью. Запутывание и загромождение.
Go to the top of the page
 
+Quote Post
RW6MKA
сообщение Mar 9 2014, 12:21
Сообщение #41


Частый гость
**

Группа: Участник
Сообщений: 163
Регистрация: 25-10-10
Из: Ростовская обл.
Пользователь №: 60 401



Уважаемые форумчане, перестаньте в присутствии новичка ругаться непонятными терминами и спорить biggrin.gif . Вопроса про оптимизацию кода я не ставил, как я уже писал, места мне вполне хватает. Я просил объяснить кусок кода и мне таки его объяснили. Возник вопрос о правильности применения того или иного типа переменной и функции и мне опять таки вежливо и подробно все объяснили. За что всем огромное спасибо. Что касается
Цитата
Хватит уже думать на уровне инструкций, переходите на уровень управления данными!
Вы извините, я не программист и не собираюсь им становиться, это просто увлечение на уровне не особо сложных полезных поделок с простенькими МК. Так что не спорьте между собой что лучше и как лучше, просто по возможности объясняйте таким новичкам как я что нам не понятно и мы будем вам очень благодарны a14.gif

Сообщение отредактировал RW6MKA - Mar 9 2014, 12:21
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Mar 9 2014, 12:26
Сообщение #42


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Не обращайте внимания, день сегодня такой... выходной. Вот народ и спорит от скуки sm.gif
Go to the top of the page
 
+Quote Post

3 страниц V   1 2 3 >
Closed TopicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 23rd July 2025 - 19:08
Рейтинг@Mail.ru


Страница сгенерированна за 0.01955 секунд с 7
ELECTRONIX ©2004-2016