Код: Выделить всё
#ifdef INVERT
#define S_CHAR(x) (~(x))
#else
#define S_CHAR(x) (x)
#endif
#define let_1 S_CHAR(seg_b| seg_c)
...
Код: Выделить всё
#ifdef INVERT
#define S_CHAR(x) (~(x))
#else
#define S_CHAR(x) (x)
#endif
#define let_1 S_CHAR(seg_b| seg_c)
...
Код: Выделить всё
~(seg_a|seg_b)Код: Выделить всё
const uint8_t charset[16] = {let_0^0xff, let_1^0xff, let_2^0xff, let_3^0xff, \Код: Выделить всё
const uint8_t charset[16] = {(uint8_t) let_0, (uint8_t) let_1...Код: Выделить всё
char a; //символьная переменная а
char *b; //указатель на символьную переменную
b = &a; //указатель b содержит адрес переменной а, то бишь какое-то двухбайтовое (для ATMega) числоКод: Выделить всё
int a = 1234567890; //целая переменная а
int* pa = &a; //указатель pa на целую переменную, в который записан адрес переменной aКод: Выделить всё
char* p = (char*)0; //указатель p на символьную переменную, в который записан 0, т.е. указатель на нулевую ячейку памяти.
//Зачем перед 0 операция приведия типа?
char* pc = &p[(int)pa]; //указатель pc на символьную переменную, в который записан адрес указателя p, смещенный на адрес в указателе pa.
//Здесь приведение типа т.к. для разных архитектур тип указателя будет разным. Для ATMega приведение не нужно, т.к. он тут и так двухбайтовый.
//Но, с другой стороный, зачем вообще приводить тип индекса к int, разве нельзя в качестве индекса использовать char или long int?
//В общем, что должно записатся в pc я не понял. & дает адрес переменной, а что она даст, если вместо переменной стоит другой адрес?
int* pi = (int*)pc; //в указатель pi записано значение указателя pc. Приведение типа т.к. pc объявлен был как char*.
printf("%d или %d\n", *pa, *pi); //не знаю, что тут выведится. Подозреваю, что выше много ошибок, и одна строка совсем непонятна Так не пойдёт? Не нужно кучи условий для препроцессора, ежели много инверсий.lix писал(а):сделайте условное определение символов индикатора в зависимости от наличия определенного макроса инвертированности сегментов.Код: Выделить всё
#ifdef INVERT #define S_CHAR(x) (~(x)) #else #define S_CHAR(x) (x) #endif #define let_1 S_CHAR(seg_b| seg_c) ...
Код: Выделить всё
#define INV_ATTR ~ //space, if not inverted
...
LED_DATA = INV_ATTR led_buf[0];
По смыслу - да, pa - указатель на int, поэтому казалось бы, правильнее объявлять именно так:baron_P писал(а):Получается в последнем куске * все таки относится к int, а не к pa. По смыслу последняя строка это pa = &a, а не *pa = &a.Код: Выделить всё
int a = 1234567890; //целая переменная а int* pa = &a; //указатель pa на целую переменную, в который записан адрес переменной a
Код: Выделить всё
int* pa;Код: Выделить всё
int* pa, pb, pc;Код: Выделить всё
int *pa, *pb, *pc, a, b, c;Код: Выделить всё
int* pa;
int* pb;
int* pc;
int a, b, c;пойдет. только препроцессор один раз отработает, а МК постоянно надо инвертировать. может Вы препроцессор жалеете? дак не надо его жалеть, он для того и придуман, чтобы облечать работу.OKF писал(а): Так не пойдёт? Не нужно кучи условий для препроцессора, ежели много инверсий.Код: Выделить всё
#define INV_ATTR ~ //space, if not inverted LED_DATA = INV_ATTR led_buf[0];
Записи "int *" и "int*" равнозначны. Всего лишь вопрос используемого мной кодестайла, в котором "int*" это тип потому пишется вместе, однострочные объявления нескольких переменных не приветствуются а с громоздкостью объявлений борются размазыванием их по местам их непосредственного использования.baron_P писал(а):Все понятно. А в вашем как-то не то чтобы очень.Получается в последнем куске * все таки относится к int, а не к pa. По смыслу последняя строка это pa = &a, а не *pa = &a.Код: Выделить всё
int a = 1234567890; //целая переменная а int* pa = &a; //указатель pa на целую переменную, в который записан адрес переменной a
Чтобы компилятор не ругался. Всякое несоответствие типов для него неожиданность и предмет для подозрений вас в недобрых намерениях либо в невнимательности. Операция непосредственного присвоения указателю численной константы исключительно опасна в рамках языка высокого уровня где пользователю в общем-то ни к чему знать и использовать такие подробности. Компилятор не может проверить корректность операции и подобно прилежному солдату ждёт приказа от вышестоящей инстанции (санкции на явное приведение типа) на исполнение этой операции.baron_P писал(а):Код: Выделить всё
char* p = (char*)0; //указатель p на символьную переменную, в который записан 0, т.е. указатель на нулевую ячейку памяти. //Зачем перед 0 операция приведия типа?
Приведение типа нужно по той-же причине что и выше - как компилятору не позволено неявно превращать число в указатель, так ему нельзя и указатель неявно превращать в число. Индекс массива должен быть целым числом - исопользование именно int не критично - насчёт char и long вы правы - но, подозреваю неявно они приведутся всё к тому-же int - разве что в случае long вас предупредят о "потере точности".baron_P писал(а):Код: Выделить всё
char* pc = &p[(int)pa]; //указатель pc на символьную переменную, в который записан адрес указателя p, смещенный на адрес в указателе pa. //Здесь приведение типа т.к. для разных архитектур тип указателя будет разным. Для ATMega приведение не нужно, т.к. он тут и так двухбайтовый. //Но, с другой стороный, зачем вообще приводить тип индекса к int, разве нельзя в качестве индекса использовать char или long int?
Найдите и распечатайте табличку приоритетов операций чтобы всегда была под рукой. Операция "array subscripting" имеет более высокий приоритет чем "address of" - следовательно сначала будет "извлечено" значение по индексу "pa" в массиве байтов "p" а затем взят его адрес и помещён в "pc". Операция в общем-то бессмысленная - чисто для иллюстрации. А "что она даст если вместо переменной стоит другой адрес" - если под "адрес" здесь понимается указатель - то адрес переменной-указателя. В данном случае она применяестя не к указателю типа (char*) а к переменной типа (char) - т.е. к элементу массива p[pa] который имеет тип char - потому и требуется взять адрес этого элемента.baron_P писал(а):Код: Выделить всё
//В общем, что должно записатся в pc я не понял. & дает адрес переменной, а что она даст, если вместо переменной стоит другой адрес?
Поскольку разыменование char* даст нам всего один байт а мы собираемся сравнить int-ы. Посему волюнтаристскими методами приказываем считать этот указатель типом int*. Тогда компилятор при разыменовании возьмёт соотвествующее количество байт:baron_P писал(а):Код: Выделить всё
int* pi = (int*)pc; //в указатель pi записано значение указателя pc. Приведение типа т.к. pc объявлен был как char*.
Код: Выделить всё
int a = 0x12345678;
int* pi = &a;
char* pc = (char*)pi;
printf("ptr to int: %x; ptr to char: %x", *pi, *pc); // вывод: "ptr to int: 12345678; ptr to char: 12"Постить такую эквилибристику без проверки в тест-программе было-бы с моей стороны весьма самонадеянноbaron_P писал(а):Код: Выделить всё
printf("%d или %d\n", *pa, *pi); //не знаю, что тут выведится. Подозреваю, что выше много ошибок, и одна строка совсем непонятна
Код: Выделить всё
#define let_1 (seg_b | seg_c)
#define let_2 (seg_a|seg_b|seg_d|seg_e|seg_g)
const uint8_t charset[] = {let_1, let_2};
void main()
{
DDRB=charset[0];
}
Код: Выделить всё
ldi r24, 0x28
out 0x17, r24
Код: Выделить всё
#define let_1 (seg_b | seg_c)
#define let_2 (seg_a|seg_b|seg_d|seg_e|seg_g)
const uint8_t charset[] = {let_1, let_2};
void main()
{
DDRB=~charset[0];
}
Код: Выделить всё
ldi r24, 0xD7
out 0x17, r24
В вашем примере меньше кода, но он требует больше умственных усилий, в отличии от моего.OKF писал(а):Я жалею внешний вид программы, коль вы не поняли.
Код: Выделить всё
cnt = 0;
rslt = OWFirst(); // Тут эти 8 байт помещаются в массив ROM_NO
while (rslt)
{
// print device found
for (i = 7; i >= 0; i--) // Тут тупо в терминал выводим содержимое ROM_NO
printf("%02X", ROM_NO[i]); //
printf(" %d\n",++cnt); // тут выводим порядковый номер найденного датчика
rslt = OWNext(); // Тут ищем еще подключенные устройства. Если нашли, то опять помещаем инфу в ROM_NO
// и всё сначала... пока все 1-wire устройства не будут найдены.
}
В целом согласен, но не думаю что здесь может быть однозначный ответ. В данном случае всё зависит от кол-ва инверсий в тексте. Если их много, тогда уже ваш пример потребует больше умственных усилий, ввиду нагромождения директив препроцессора. Либо же придётся дублировать участки программы для наглядности, что тоже имеет недостатки.lix писал(а): В вашем примере меньше кода, но он требует больше умственных усилий, в отличии от моего.
В LED_DATA = INV_ATTR led_buf[0]; есть лишняя сущность это INV_ATTR; она нужна только для контроллера, прграммисту он ней можно не знать, ему достаточно знать, что мы выводим такой-то символ.
как он представлен, прямо или инверсно, здесь это не важно. это важно только когда мы определяем представления символов. в моем коде это выражено более наглядно, и из него видно что к чему, он самодокументирован.
В вашем случае, придется дописать коментарий о том что для инверсии символов необходимо определить INV_ATTR как ~, иначе оставить пустым. INV_ATTR должен быть определен в любом случае, иначе будет ошибка, или нужно править код вывода символов, что не является хорошей практикой.
Код: Выделить всё
void renew_screen(uint_fast8_t scr_id){// flash ram
// "тело" закомментировано 1736 58
lcd_clear(); //1740 58
switch(scr_id){
case 1:{ //1740 58
uint_fast8_t *p; //1740 58
char ico[2][2]={{2,3},{4,5}}, b[16]; //1740 58
//1 line
lcd_block(ico[0],2); //1798 58 58 байт занял вызов
p=&rom[0][0]; //1798 58
eeprom_read_block(b, (const void*)(int)*p,*(p+1)); //1816 58
b[0]=light_state&(1<<UV_TOP)?1:0; //1816 58
b[5]=light_state&(1<<UV_BOT)?1:0; //1816 58
b[10]=light_state&(1<<RED)?1:0; //1816 58
lcd_block(b,*(p+1)-1); //1862 58 а здесь - 46 байт
//2 line
lcd_cmd(0xC0); //1866 58
//lcd_gotoxy(0,1); //1884 58
lcd_block(ico[1],2); //1892 58 тут вообще всего 8 байт...Код: Выделить всё
char* pc = &p[(int)pa];Код: Выделить всё
int a = 1234567890;
int* pa = &a; //*pa == 1234567890
char* p = (char*)0; //p == 0
char* pc = &p[(int)pa]; //pc == p+pa == pa, но тут pc указатель на char, а pa указатель на int.
//И тогда *pc == 0b11010010, т.е. младшие 8 бит числа 1234567890, содержащегося в *pa
int* pi = (int*)pc; //pi == pc, но с преобразованием типа
printf("%d или %d\n", *pa, *pi); //благодаря преобразованию выведится: 1234567890 или 1234567890Обязательно устаканятся. Неочевидные операции просто прорабатывайте тщательно - например создайте тест-програмку на PC и погоняйте её в отладчике - чтобы убедиться что у вас сложилась правильное понимание того как работает та или иная конструкция. А после прохождения такого "квеста" ещё и удовольствие получите.baron_P писал(а):Наверное, лучшим решением для меня будет обход стороной неочевидных операций с указателями. Может когда-нибудь потом оно в голове устаканится.