|
|
  |
Вопрос к знатокам С. |
|
|
|
Oct 20 2008, 16:04
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Возник тут вопрос. Кусочек программы можно написать двумя способами, но с одним и тем же правильным результатом (компилятор avr-gcc 4.1.2). Вопрос: это можно взять на вооружение? И что стандарт может нам сказать по этому поводу? Спасибо. Код //============================================ unsigned char temp;
temp = *uart->pUDR; // Очищаем буфер 3-его уровня. temp = *uart->pUDR; temp = *uart->pUDR;
//============================================ *uart->pUDR; // Очищаем буфер 3-его уровня. *uart->pUDR; *uart->pUDR;
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Oct 20 2008, 17:27
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Спасибо за подсказку. Я, по незнанию, наверное, всегда делал присвоение промежуточной переменной. Что-то подсказывает, что второй вариант тоже законный, но тщательное чтение стандарта C99 не помогло выявить пункт, который это подтверждает. Не могли бы более знающие товарищи навести на этот пункт (пункты)? С другой стороны, присваивание промежуточной переменной имеет одно преимущество: даже неискушённые в глубоких тонкостях языка Си поймут, что имелось в виду. На мой взгляд, это сильное преимущество. Не следует жертвовать читаемостью кода.
|
|
|
|
|
Oct 20 2008, 18:05
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(scifi @ Oct 20 2008, 21:27)  Спасибо за подсказку. Всегда рад  Цитата(scifi @ Oct 20 2008, 21:27)  Я, по незнанию, наверное, всегда делал присвоение промежуточной переменной. Что-то подсказывает, что второй вариант тоже законный, но тщательное чтение стандарта C99 не помогло выявить пункт, который это подтверждает. Не могли бы более знающие товарищи навести на этот пункт (пункты)? С другой стороны, присваивание промежуточной переменной имеет одно преимущество: даже неискушённые в глубоких тонкостях языка Си поймут, что имелось в виду. На мой взгляд, это сильное преимущество. Не следует жертвовать читаемостью кода. На мой взгляд читаемость лишь улучшается. А вот первоисточник сего финта найти надо, да как вообще это называется очень хочется узнать, чтоб знать хоть что искать.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Oct 20 2008, 18:17
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(scifi @ Oct 20 2008, 19:27)  ...но тщательное чтение стандарта C99 не помогло выявить пункт, который это подтверждает. Кроме прочитать, нужно еще и суть понимать. 1.Упоминание имени переменной означает обращение к ней. Это основы основ. Какие "подтверждения" еще требуются? 2.Для того, что бы "бесполезные" обращения не были выкинуты компилятором есть клбчевое слово volatile. Поиск по доукменту, надеюсь работает? Цитата С другой стороны, присваивание промежуточной переменной имеет одно преимущество: даже неискушённые в глубоких тонкостях языка Си поймут, что имелось в виду. На мой взгляд, это сильное преимущество. Не следует жертвовать читаемостью кода. Вcе с точностью до наоборот 1. Никаких "тонкостей" нет напрочь - это самые основы. 2. Введение неких ненужных переменных, получение воплей о их ненужности от компилятора, закрытие этих вопплей - да какая уж тут, простите, в результате "читаемость"!? Цитата А вот первоисточник сего финта найти надо, "Финты" это как-раз с лишней переменной  не знаю, какой "умник" такой финт и с какого бодуна применил, но думаю, что его уже не найти
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 20 2008, 18:35
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(zltigo @ Oct 20 2008, 22:17)  1.Упоминание имени переменной означает обращение к ней. Это основы основ. Какие "подтверждения" еще требуются? Контрпример: взятие адреса переменной. Имя упоминается, а обращения нет. После дополнительного прочтения стандарта начинает вырисовываться: - The expression in an expression statement is evaluated as a void expression for its side effects. - A postfix expression followed by the -> operator and an identifier designates a member of a structure or union object. The value is that of the named member of the object to which the first expression points, and is an lvalue. Действительно, есть значение выражения, а для его получения необходимо обращение к полю сруктуры.
|
|
|
|
|
Oct 20 2008, 19:11
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(scifi @ Oct 20 2008, 20:35)  Контрпример: взятие адреса переменной. Имя упоминается, а обращения нет. На то это и ДРУГАЯ ОПЕРАЦИЯ. Совсем другая - взятие адреса, а не значения. Цитата После... Эко куда Вас понесло..... Зачем?
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 20 2008, 19:34
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Цитата(zltigo @ Oct 20 2008, 22:17)  1.Упоминание имени переменной означает обращение к ней. Цитата(zltigo @ Oct 20 2008, 23:11)  На то это и ДРУГАЯ ОПЕРАЦИЯ. Совсем другая - взятие адреса, а не значения. Я запутался... Взятие адреса - это совсем другая операция по сравнению с упоминанием имени переменной? То есть "var++" - это упоминание имени, а "&var" - нет? Цитата(zltigo @ Oct 20 2008, 23:11)  Эко куда Вас понесло..... Зачем? Затем, что вопрошающий сказал: "И что стандарт может нам сказать по этому поводу?" Посему стараюсь приводить цитаты из стандарта, имеющие отношение к данному вопросу.
|
|
|
|
|
Oct 20 2008, 19:53
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Цитата(scifi @ Oct 20 2008, 23:34)  Я запутался... Взятие адреса - это совсем другая операция по сравнению с упоминанием имени переменной? То есть "var++" - это упоминание имени, а "&var" - нет? Если раскрутить, то получим такую цепочку: var++; var += 1; var = var + 1; Отсюда видно, что что тут происходит не только упоминание переменной всуе  А взятие адреса - это действие, которое никак не отражается на самой переменной - происходит лишь загрузка в индексный регистр адреса переменной.
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Oct 21 2008, 15:57
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(demiurg_spb @ Oct 20 2008, 21:53)  А взятие адреса - это действие, которое никак не отражается на самой переменной - происходит лишь загрузка в индексный регистр адреса переменной. Есть еще и другие операции, например декларирование, sizeof, ... Цитата Посему стараюсь приводить цитаты из стандарта, имеющие отношение к данному вопросу. Ну не обязан стандарт заменять учебник арифметики. Пишем: a = b проговариваем как первоклашки на уроке арифметики - "взяли значение переменной 'b' и присвоили его переменной 'a'" Теперь пишем: b проговариваем - "взяли значение переменной 'b'". И... и все. Все, что нам надо, мы сделали! Ничего лишнего и мутного. Чего не понятно-то? Какие какие такие "тонкости C"? Цитата(sergeeff @ Oct 21 2008, 17:08)  К примеру MSVS 2008 для ARM в обоих случаях генерит одинаковый код. Ну и что? Слава оптимизации! Сначала читатель продирается через нагрможденение ненужностей, потом компилятор. Если оба поняли, что все эти "финты" не нужны совсем, то результаты, етественно будут одинаковые - БЕЗ ФИНТОВ.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 17:01
|
Профессионал
    
Группа: Свой
Сообщений: 1 481
Регистрация: 10-04-05
Пользователь №: 4 007

|
Без финтов - это отлично, но!!! - очень непривычно. Чтение из переменной очевидно, когда оно стоит справа от знака присваивания. И когда этот знак опущен это и вызывает недоумение и неприятие.
Я думаю, если бы разместить где-нибудь на форумах вопрос типа: "Что означает выражение для переменной volatile int x?: x;"
абсолютное большинство ответит неправильно. Посему, учитывая, что всех не переучишь, и почти все люди работают в коллективах, я бы именно из этих соображений оставил бы: int temp = x;.
Коллеге zltigo респект за неординарный подход. Тем более, что почти аналогичное использование чтения переменной, например, в while(x) ни у кого вопросов не вызвало бы.
|
|
|
|
|
Oct 21 2008, 17:42
|
Гуру
     
Группа: Свой
Сообщений: 3 020
Регистрация: 7-02-07
Пользователь №: 25 136

|
Итак, итоги: 1) Согласно стандарту языка для чтения volatile переменной var достаточно написать Код var; Кому интересно, могу подкрепить это цитатами из стандарта. 2) Очевидно, что такой код не проходит тест "даже моя бабушка поймёт, что это значит". Другими словами, читаемость кода страдает. 3) Вывод. Каждый решает сам, что лучше: - пожетворать читаемостью кода - бороться с предупреждениями компилятора при присваивании вспомогательной переменной Код dummy = var; Итак, задача сведена к спору "читаемость кода против подавления предупреждений компилятора". Как известно, такой спор заведомо неразрешим, так что дальнейшие дискуссии результата не принесут :-)
|
|
|
|
|
Oct 21 2008, 17:52
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(scifi @ Oct 21 2008, 19:42)  Другими словами, читаемость кода страдает. Это утверждение абсолютно ложное  , посему и "вывод" такой-же. Код var; // Это читабельно А что-то типа такого, даже максимально обвешенного для понимания ненужности "финтов": Код { int tmp = var; tmp = tmp; } // Много, много хуже. А такое: Код tmp = var; // Вообще безобразие
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 20:38
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(sergeeff @ Oct 21 2008, 20:01)  Чтение из переменной очевидно, когда оно стоит справа от знака присваивания. К слову: совершенно неочевидно, что занесение значения в переменную слева от знака присваивания является лишь побочным эффектом опрератора "=", но это так и есть. Цитата(scifi @ Oct 21 2008, 20:42)  1) Согласно стандарту языка для чтения volatile переменной var достаточно написать Код var; Кому интересно, могу подкрепить это цитатами из стандарта. Очень интересно. ИАР для АРМов, версии 4.30 точно (более старшие не проверял), с легкостью выкидывает такие обращения. ReAl объяснил это мутностью стандарта в этой части. Самому искать было лень. Но раз вы предлагаете найти - с удовольствием почитаю цитаты. Цитата(scifi @ Oct 21 2008, 20:42)  - бороться с предупреждениями компилятора при присваивании вспомогательной переменной Код dummy = var; Все встречавшиеся мне компиляторы убирали предупреждение при добавлении строчки dummy = dummy;
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 21 2008, 20:42
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Сергей Борщ @ Oct 21 2008, 22:38)  Очень интересно. ИАР для АРМов, версии 4.30 точно (более старшие не проверял), с легкостью выкидывает такие обращения. Любой вменяемый компилятор выкидывает, но ЕСЛИ НЕ volatile. В данном случае это volatile, а не для volatile - выкидывает правильнно, ибо пустое и бессмысленное действие. Цитата ReAl объяснил это мутностью стандарта в этой части. Никакой мутности в отношении volatile переменных в C99 нет.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 20:51
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Сергей Борщ @ Oct 21 2008, 22:38)  Все встречавшиеся мне компиляторы убирали предупреждение при добавлении строчки dummy = dummy; Наиблее часто встречающийся  с "финтами", но безграмотный вариант  . Однозначный и независимый от компилятора и опимизации: Код (void)dummy; Цитата(Сергей Борщ @ Oct 21 2008, 22:46)  Вот сейчас специально поставлю ИАР и приведу листинг. Именно volatile переменную. Момент... Не стоит  . Не получится.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 20:59
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(zltigo @ Oct 21 2008, 23:51)  Не стоит  . Не получится. Если бы не получалось, я бы в эту ветку не писал: Пожалуйста: Код OS_INTERRUPT void Timer_ISR() { OS::TISRW ISRW;
T1IR; // = T1IR; // clear int flag IO0SET = (1 << 29); На строку с комментарием предупреждение: Warning[Pe174]: expression has no effect D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\Src\main.cpp 108 CODE ####################################################################### ####### # # # IAR ARM ANSI C/C++ Compiler V4.30A/W32 EVALUATION 21/Oct/2008 23:47:48 # # Copyright 1999-2005 IAR Systems. All rights reserved. # # # # Cpu mode = interwork # # Endian = little # # Stack alignment = 4 # # Source file = D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # Src\main.cpp # # Command line = D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # Src\main.cpp -D LPC2119 -lCN # # D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # List\ -o D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-E # # ventFlag\Obj\ -s9 --debug --cpu_mode thumb --endian # # little --cpu ARM7TDMI-S --stack_align 4 --interwork # # -e --fpu None --eec++ --dlib_config # # D:\Programs\IAR\arm\LIB\dl4tptinl8n.h -I # # D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # Src\ -I D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-Ev # # entFlag\..\scmRTOS\Common\ -I # # D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # ..\scmRTOS\ARM7\ -I D:\Programs\IAR\arm\INC\ # # List file = D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # List\main.lst # # Object file = D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\ # # Obj\main.r79 # # # # # ############################################################################## ......................... \ In segment DATA_AN, at 0xe0008000 \ <unnamed> volatile __data _A_T1IR \ _A_T1IR: \ 00000000 DS8 4 ......................... 104 OS_INTERRUPT void Timer_ISR() 105 { \ ??Timer_ISR: \ 00000000 04E04EE2 SUB LR,LR,#+0x4 \ 00000004 1F502DE9 STMDB SP!,{R0-R4,R12,LR} ;; Push 106 OS::TISRW ISRW; \ 00000008 70409FE5 LDR R4,??Timer_ISR_1 ;; Kernel \ 0000000C 1400D4E5 LDRB R0,[R4, #+0x14] \ 00000010 010080E2 ADD R0,R0,#+0x1 \ 00000014 1400C4E5 STRB R0,[R4, #+0x14] 107 108 T1IR; // = T1IR; // clear int flag 109 IO0SET = (1 << 29); \ 00000018 4E02A0E3 MOV R0,#-536870908 \ 0000001C A00B80E3 ORR R0,R0,#+0x28000 \ 00000020 8015A0E3 MOV R1,#+0x20000000 \ 00000024 001080E5 STR R1,[R0, #+0]
Компилятор не такой и старый, сильно моложе чем C99 не говоря уже о C89: Цитата IAR C/C++ Compiler for ARM 4.30A Evaluation (4.30.1.237) D:\Programs\IAR\arm\bin\iccarm.exe 09.02.2005 21:13:44, 9539584 bytes Поэтому и хочется увидеть цитату из стандарта. А самому искать лень  GCC даже в версии 3.2.3 от 2003(?) года не выкидывает.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 21 2008, 21:19
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Сергей Борщ @ Oct 21 2008, 22:59)  На строку с комментарием предупреждение: Warning[Pe174]: expression has no effect Это типичное сообщение при выкидывании не volatile переменной. Просто T1IR неведомо как описан. Давай чистый эксперимент. Код volatile int dummy = 0; ..... function() { dummy; Поскольку я пишу на "С" уже лет 20, именно так, в том числе и под IAR, года 4, то в результате СИШНОГО КОМПИЛЯТОРА я более, чем уверен. В догонку: Код ############################################################################## # # # IAR ARM ANSI C/C++ Compiler V4.42A/W32 22/Oct/2008 01:13:05 # # Copyright 1999-2005 IAR Systems. All rights reserved. # # # # Cpu mode = arm # # Endian = little # # Stack alignment = 8 # # Source file = D:\ARM_WORK\auc\MAIN\fiqhandl.c # # Command line = D:\ARM_WORK\auc\MAIN\fiqhandl.c -D LPC2000_IAR -lC # # D:\ARM_WORK\auc\Works_Kernel\List\ -lA # # D:\ARM_WORK\auc\Works_Kernel\List\ --remarks -o # # D:\ARM_WORK\auc\Works_Kernel\Obj\ -s9 --cpu_mode # # arm --endian little --cpu ARM7TDMI-S --stack_align # # 8 --warnings_affect_exit_code # # --no_path_in_file_macros --migration_preprocessor_ex # # tensions -e --require_prototypes --fpu None # # --dlib_config "D:\IAR\Embedded # # Workbench\arm\LIB\dl4tpannl8n.h" -I # # D:\ARM_WORK\auc\..\COMMON\RTOS\portable\IAR\LPC2000\ # # -I D:\ARM_WORK\auc\..\COMMON\RTOS\include\ -I # # D:\ARM_WORK\auc\..\COMMON\include\ -I # # D:\ARM_WORK\auc\main\include\ -I "D:\IAR\Embedded # # Workbench\arm\INC\" --inline_threshold=8 # # List file = D:\ARM_WORK\auc\Works_Kernel\List\fiqhandl.lst # # Object file = D:\ARM_WORK\auc\Works_Kernel\Obj\fiqhandl.r79 # # # # # ##############################################################################
D:\ARM_WORK\auc\MAIN\fiqhandl.c 1 2 #include <stdlib.h> 3 #include "RTOS.h"
\ In segment DATA_AN, at 0xe01fc140 \ union <unnamed> volatile __data _A_EXTINT \ _A_EXTINT: \ 00000000 DS8 4 4 #include "fiqhandl.h" 5
\ In segment DATA_Z, align 4, align-sorted 6 volatile int dummy1; \ dummy1: \ 00000000 DS8 4
\ In segment DATA_Z, align 4, align-sorted 7 int dummy2; \ dummy2: \ 00000000 DS8 4 8 9 //--------------------------------------------------------------------------- 10 // 11 //---------------------------------------------------------------------------
\ In segment CODE, align 4, keep-with-next 12 __fiq __arm void FIQ_ISR_handler(void) 13 { 14 15 dummy1; \ FIQ_ISR_handler: \ 00000000 14809FE5 LDR R8,??FIQ_ISR_handler_0 ;; dummy1 \ 00000004 008098E5 LDR R8,[R8, #+0] 16 dummy2; ^ Warning[Pe174]: expression has no effect 17 18 Оба варианта - c выкидыванием и без. Более старях компиляторов не держу, но если что, то и на самом старом и кривом имеющимся у меня BCC 3.1 будет тоже самое. Ибо вариантов нет.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 21:34
|

неотягощённый злом
     
Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643

|
Попробовал на древнем: Цитата # IAR Atmel AVR C/EC++ Compiler V3.20C/W32, Evaluation Version 22/Oct/2008 01:26:48 # Тоже всё ок: Код volatile unsigned char my_dummy; void main(void) { my_dummy; } //==================================================== листинг: 85 my_dummy; \ 00000004 .... LDI R26,LOW(??statetext) \ 00000006 .... LDI R27,(??statetext) >> 8 \ 00000008 01FD MOVW R31 : R30,R27 : R26 \ 0000000A 8501 LDD R16,Z+9
--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
|
|
|
|
|
Oct 21 2008, 21:38
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(zltigo @ Oct 22 2008, 00:19)  Это типичное сообщение при выкидывании не volatile переменной. Просто T1IR неведомо как описан. Я специально дал вырезку из листинга, в которой он сам эту переменную описывает как volatile: Код \ In segment DATA_AN, at 0xe0008000 \ <unnamed> volatile __data _A_T1IR \ _A_T1IR: \ 00000000 DS8 4 По поводу типичности сообщений один человек очень красиво написал на AVRFreaks: Цитата In the case of warnings, the answer never lies in the C standard. The C standard does not require any warnings. We are trying to read the minds of the gods. As a rule, a compiler issues a warning when you have done something that is allowed, but the compiler suspects might not be what you intended. Цитата(zltigo @ Oct 22 2008, 00:19)  Давай чистый эксперимент. Не вопрос: Код volatile int dummy = 0; void function() { dummy; } //--------------------------------------------------------------------------- OS_INTERRUPT void Timer_ISR() { OS::TISRW ISRW;
T1IR; // = T1IR; // clear int flag Цитата Warning[Pe174]: expression has no effect D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\Src\main.cpp 106 Warning[Pe174]: expression has no effect D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\Src\main.cpp 113 Цитата(zltigo @ Oct 22 2008, 00:19)  Поскольку я пишу на "С" уже лет 20, именно так, в том числе и под IAR, года 4, то в результате СИШНОГО КОМПИЛЯТОРА я более, чем уверен. Я не хочу спорить. ИАР вполне себе сишный компилятор и становится все лучше год от года. Я лишь хочу разобраться - это была бага или есть фича. Если стандарт описывает поведение однозначно - бага. Если нет - фича, и каждую версию каждого компилятора надо будет проверять на необходимость workaround с временной переменной, что я и делаю пока не разобрался в этом вопросе досконально. И как ни крути, хоть вариант без временной переменной красив, но, как видим, не всегда работает. А вариант с временной переменной работает всегда. Следовательно надо разобраться, кто виноват в непортируемости - компилятор, который не соответствует стандарту или программист, понадеявшийся на нерегламентируемое стандартом поведение компилятора. Цитата(zltigo @ Oct 22 2008, 00:19)  В догонку: В новой версии behaviour изменился  Все, спать. Иначе придется самим в стандарте копаться
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Oct 21 2008, 21:53
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Сергей Борщ @ Oct 21 2008, 23:38)  ИАР вполне себе сишный компилятор и.... Тем не менее, ты компилишь П Л Ю С О В Ы М (точнее недоплюсовым  ) компилятором, почему-то рассуждая о C99. Кроме того, ты получил более, чем вменяемый Warning. Цитата(Сергей Борщ @ Oct 21 2008, 23:38)  ...но, как видим, не всегда работает Я бы поверил, в баг конкретного компилятора, если-бы не работал и с этой версией компилятора, причем гарантированно, многократно и постоянно использовал и использую, как минимум: SSPDR; для очистки FIFO SSP при полудуплексной передаче. Хидеры традиционно использую самописные. Цитата(Сергей Борщ @ Oct 21 2008, 23:38)  По поводу типичности сообщений один человек очень красиво написал на AVRFreaks: В данном случае я говорю о типичном собщении совершенно конкретного компилятора.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 21 2008, 22:02
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Сергей Борщ @ Oct 21 2008, 23:55)  Не думал, что в этом вопросе он отличается от неплюсового. Не думаю, что отличается, поскольку это совершенно естественное-разумное поведение. Любое другое не берусь даже хоть как-то объяснить...Полубаг "старого" компилятора  ? P.S. Попробовал. Любая версия V4-V5 плюсовых компиляторов от IAR выдает warning. Странно.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Oct 22 2008, 04:41
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(zltigo @ Oct 22 2008, 00:51)  Однозначный и независимый от компилятора и опимизации: Код (void)dummy; Вы знаете, попробовал - не работает. Все равно ворнинг. IAR AVR 4.3 (EEC++). Код: Код byte dummy; dummy = UDR0; dummy = UDR0; dummy = UDR0; (void) dummy; UDR0 - из стандартного иаровского хидера: Код SFR_B_R(0x1F, AVR) Expands to: * __io union { * unsigned char AVR; // The sfrb as 1 byte * struct { // The sfrb as 8 bits * unsigned char AVR_Bit0:1, * AVR_Bit1:1, * AVR_Bit2:1, * AVR_Bit3:1, * AVR_Bit4:1, * AVR_Bit5:1, * AVR_Bit6:1, * AVR_Bit7:1; * }; * } @ 0x1F;
SFR_B_R(0x0C, UDR0) /* USART0 I/O Data Register */ Ворнинг давится только dummy=dummy  PS начал читать тему - думал можно будет избавиться от этого некрасивого кода
|
|
|
|
|
Oct 22 2008, 05:53
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Цитата(Непомнящий Евгений @ Oct 22 2008, 07:41)  Вы знаете, попробовал - не работает. Все равно ворнинг. IAR AVR 4.3 (EEC++). Код: Код byte dummy; dummy = UDR0; dummy = UDR0; dummy = UDR0; (void) dummy; UDR0 - из стандартного иаровского хидера: ... Ворнинг давится только dummy=dummy  PS начал читать тему - думал можно будет избавиться от этого некрасивого кода  В Вашем случае прочитать UDR0 без dummy можно и так: Код if (UDR0); Правда не знаю насколько это читабельно смотрится. На любителя. В плюсах работает и я уже привык.
|
|
|
|
|
Oct 22 2008, 06:40
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(Непомнящий Евгений @ Oct 22 2008, 06:41)  IAR AVR 4.3 (EEC++)..... Ну что я могу сказать - много значит cтранностей в IARовском недо плюсовом компиляторе  . Подчеркиваю еще раз ПЛЮСОВОМ, а тема начинслась как C/C99. Если var; я в своих плюсовых программах использую редко, поскольку от железа они обычно далеки, то уж (void)var; ввиде макросика USED(var) - в процессе написания ну очень часто. При этом С компилятор от IAR ведет себя абсолютно ожидаемо, впрочем, как и абсолютно все C используемые мной за долгие годы. В оправдание плюсового IAR, могу сказать только то, что warnings он тем не менее генерит...
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Nov 10 2008, 11:49
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Сергей Борщ @ Oct 21 2008, 22:38)  ReAl объяснил это мутностью стандарта в этой части. Самому искать было лень. Ой, не помню... Кажется, разночтение было на тему - обязательно ли в цепочке Код int a; volatile int v; a = v = 0; для записи в a зачитывать из v. Согласно стандарту значением присваивающего выражения есть значение, которое будет записано в левую часть после присваивания. Я утверждал, что в случае volatile-переменной значение неизвестно и нужно перезачитать. Но какой-то компилятор радостно в таком случае явно писал нули во все переменные, что на мой взгляд неправильно. В каком-то обсуждении (RU.C-CPP или ещё где-то) было сказано, что смысл строки стандарта не "что там будет сидеть после записи", а "что туда будет записано", а это не зависит от volatile-ности. Я не стал разбираться дальше, "юридический английский" у меня не настолько... :-( Впрочем, поскольку я всё равно был уверен, что надо перезачитывать, я всё равно не использовал значение присваивающего выражения, если в левой части volatile, так как это снижает читаемость - глаз воспринимает как значение правую часть, а реально будет прочитанное из левой. т.е. не использовал while( (volatile_var = var) ), function( volatile_var = var), return (volatile_var = var); Однако считаю, что в случае отдельно стоящей volatile-переменной в духе Код UDR; компилятор должен провести все действия, необходимые для вычисления выражения (в данном случае только прочесть переменую, в случае с UDR+1; - прочесть и прибавить единицу), а только потом обнаружить, что результат-то никому не нужен и начать оптимизатором "отматывать" назад ненужные действия - пока не упрётся в запрет, поставленный квалификатором volatile. Т.е. чтение volatile-переменной должно остаться. Если какой-то компилятор этого не делает (это тоже, кажется, где-то в аське обсуждалось), то надо внимательно ещё раз прочесть стандарт и попытаться поругаться. Цитата(sergeeff @ Oct 21 2008, 19:01)  Без финтов - это отлично, но!!! - очень непривычно. Чтение из переменной очевидно, когда оно стоит справа от знака присваивания. И когда этот знак опущен это и вызывает недоумение и неприятие. А многие не понимают указателей. А у многих вызывает недоумение запись Код value = ( flag ? sin : cos)(x); несмотря на то, что она, на мой взгялд, гораздо более читабельна, чем алгол-68 Код value := if flag then sin else cos fi (x) Если из С повыбрасывать всё то, что вызывает недоумение у новичков, то что останется? Цитата(sergeeff @ Oct 21 2008, 19:01)  Код volatile int x; ... x ? : x; Прочесть x, если он равен нулю - прочесть его ещё раз. С прочитанными значениями больше ничего не делать. Цитата(sergeeff @ Oct 21 2008, 19:01)  Коллеге zltigo респект за неординарный подход. Подход правильный, называется "знать инструмент, которым пользуешся". Цитата(scifi @ Oct 21 2008, 19:42)  Итак, итоги: ... 2) Очевидно, что такой код не проходит тест "даже моя бабушка поймёт, что это значит". Другими словами, читаемость кода страдает. Читаемость кода завиит от подготовки читающего. Так можно дойти и до "отмены" ++ и переходу от ++i к i = i + 1; (во всяком случае побыстрее запретить применение i++, так как это вообще непонятно). Вменяемый человек, наткнувшись первый раз, при помощи стандарта либо более опытных товарищей разберётся и дальше для него читаемость будет нормальная. Цитата(Сергей Борщ @ Oct 21 2008, 22:59)  На строку с комментарием предупреждение: Warning[Pe174]: expression has no effect D:\Projects\Req\scmRTOS\Samples\LPC2xxx\1-EventFlag\Src\main.cpp 108 Странно... Всё-таки странно. Может всё-же пройтись ещё по стандарту и попробовать с ними поругаться?
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 11 2008, 10:09
|

Шаман
     
Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221

|
Цитата(ReAl @ Nov 10 2008, 13:49)  Однако считаю, что в случае отдельно стоящей volatile-переменной в духе Код UDR; компилятор должен провести все действия, необходимые для вычисления выражения (в данном случае только прочесть переменую, в случае с UDR+1; - прочесть и прибавить единицу), а только потом обнаружить, что результат-то никому не нужен и начать оптимизатором "отматывать" назад ненужные действия - пока не упрётся в запрет, поставленный квалификатором volatile. Т.е. чтение volatile-переменной должно остаться. Если какой-то компилятор этого не делает (это тоже, кажется, где-то в аське обсуждалось), то надо внимательно ещё раз прочесть стандарт и попытаться поругаться. Те же самые рассуждения можно провести и в случае Код if(UDR); и результат по логике рассуждений будет тем же самым, но ошибка в случае с if не выдаётся.
|
|
|
|
|
Nov 11 2008, 10:56
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Код volatile int x; x ? : x; IAR AVR 4.12 выдает ошибки Error[Pe029]: expected an expression Error[Pe053]: expected a ":" Как к этому относится с учетом вышесказанного?
|
|
|
|
|
Nov 11 2008, 11:13
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(VladimirYU @ Nov 11 2008, 13:56)  Как к этому относится с учетом вышесказанного? Правильно ругается: стандарт не предусматривает выбрасывания операндов из :?. Можно написать так: Код volatile int x; x ? 0 : x;
|
|
|
|
|
Nov 11 2008, 11:13
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
а, простите, разве писать читаемый всеми код - это уже признак дурного стиля программирования? по-моему, во все времена было наоборот... и на написанный без извратов код ни один компилятор не станет ругаться... Код uchar temp = UDR; по-моему, понятно абсолютно всем, не вызывает ошибок и ворнингов, компилится в ту же самую единственную команду... P.S. Имхо, то, что язык позволяет писать конструкции, с трудом поддающиеся расшифровке "простыми смертными", еще не означает, что так писать - хорошо или круто. в русском языке много матерных оборотов, однако их использование в речи все-же осуждается... равно как и арго и т.п. сленг...
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 11 2008, 11:23
|
Знающий
   
Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153

|
Цитата(VladimirYU @ Nov 11 2008, 14:56)  Код volatile int x; x ? : x; ... Как к этому относится с учетом вышесказанного? Это расширение gcc: http://hubbard.engr.scu.edu/embedded/avr/d...ml#Conditionals
|
|
|
|
|
Nov 11 2008, 11:42
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(aaarrr @ Nov 11 2008, 15:13)  Можно написать так: Код volatile int x; x ? 0 : x; Все правильно, но вот конструкция, например Код char tmp = SPSR; // tmp далее не исп.; генерит код чтения регистра а просто Код SPSR; нет. М.б. все таки "тупое" явное чтение в переменную более надежно, чем варианты предлагаемые гуру. IAR 4.12 оптимизация отключена. Цитата(Непомнящий Евгений @ Nov 11 2008, 15:23)  Спасибо Может и не убедительный, но все же аргумент в пользу "тупых" конструкций.
|
|
|
|
|
Nov 11 2008, 11:43
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(VladimirYU @ Nov 11 2008, 14:42)  Все правильно, но вот конструкция, например Код char tmp = SPSR; // tmp далее не исп.; генерит код чтения регистра а просто Код SPSR; нет. Значит SPSR не volatile, или используется старый плюсовый IAR. По-моему, дискуссия пошла на второй круг.
|
|
|
|
|
Nov 11 2008, 11:57
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(aaarrr @ Nov 11 2008, 15:43)  Значит SPSR не volatile, или используется старый плюсовый IAR. По-моему, дискуссия пошла на второй круг. SPSR это регистр статуса SPI, все I/O регистры описаны в .h как VOLATILE компилятор отнюдь не старый, проверил на IAR AVR 5.10 то же самое. Может быть из-за моей неграмотности, но я так и не понял это все же баг компилятора, или если данная форма отдана стандартом на реализацию, тогда фитча.
|
|
|
|
|
Nov 11 2008, 12:17
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(aaarrr @ Nov 11 2008, 16:02)  Листинг посмотреть можно? Если "тупо" Код 10 { 11 char tmp = SPCR; \ 00000000 B10D [b]IN R16, 0x0D[/b] \ 00000002 2F20 MOV R18, R16 12 13 return; \ 00000004 E000 LDI R16, 0 \ 00000006 E010 LDI R17, 0 \ 00000008 9508 RET \ 0000000A REQUIRE _A_SPCR 14 } Если с "изыском" Код 9 int main() \ main: 10 { 11 SPCR; 12 13 return; \ 00000000 E000 LDI R16, 0 \ 00000002 E010 LDI R17, 0 \ 00000004 9508 RET 14 } Цитата(aaarrr @ Nov 11 2008, 16:02)  Листинг посмотреть можно? Еще один из обсуждавшихся вариантов: Код 9 int main() \ main: 10 { 11 [b](void)SPCR;[/b] 12 13 return; \ 00000000 E000 LDI R16, 0 \ 00000002 E010 LDI R17, 0 \ 00000004 9508 RET 14 } То же самое. Чтения нет.
|
|
|
|
|
Nov 11 2008, 12:26
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(zltigo @ Nov 11 2008, 16:19)  Это вообще просто "C" - начиная с K&R. Совершенно переносимо. Только если выражение после ? не пустое. Цитата Therefore, the expression
x ? : y has the value of x if that is nonzero; otherwise, the value of y.
This example is perfectly equivalent to
x ? x : y Евгений абсолютно прав.
|
|
|
|
|
Nov 11 2008, 13:17
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(IgorKossak @ Nov 11 2008, 12:09)  Те же самые рассуждения можно провести и в случае Код if(UDR); и результат по логике рассуждений будет тем же самым, но ошибка в случае с if не выдаётся. Ну можно и Код for( int i = 0; i < 1; ++i) if(UDR); и результат опять будет тот же самый :-) А на Код if(UDR); gcc выдаёт предупреждение "warning: empty body in an if-statement", а вот на Код (void)UDR; не выдаёт ничего и правильно делает. Зачем мне лишние предупреждения? Собственно, в том конкретном случае, о котором говорил Сергей, тоже не ошибка была, а предупреждение, причём предупреждение правильное ("выражение ничего не делает"), которое помогло поймать неправильность компиляции :-) И если компилятор нормально отрабатывает if(UDR);но шалит на UDR;то просто надо что-то делать с компилятором, хотя бы жаловаться в ООН, а как временную меру написать макрос, который прячет плохое поведение компилятора (чтобы спинной мозг не привыкал писать обходную конструкцию, а глаза не привыкали видеть - я, например, если увижу if(UDR); то в первую очередь подумаю что тут ошибка, проскочила лишняя ; ). Либо кто-то должен доказать мне со ссылками на стандарт, что он имеет право так делать. Цитата(ARV @ Nov 11 2008, 13:13)  а, простите, разве писать читаемый всеми код - это уже признак дурного стиля программирования? ... P.S. Имхо, то, что язык позволяет писать конструкции, с трудом поддающиеся расшифровке "простыми смертными", еще не означает, что так писать - хорошо или круто. в русском языке много матерных оборотов, однако их использование в речи все-же осуждается... равно как и арго и т.п. сленг... Что значит "всеми"? Совсем-совсем всеми? Вот Ваш P.S. с все поймут? Или "все, имеющие уровень образования выше некоторого порога"? И причём тут маты? Так что, на мой взгляд, тут скорее "в русском языке много разных способов посттроения предложений, однако для того, чтобы быть понятым всеми, стоит избегать сложных предложений, да и вообще - наличие запятых не ещё не означает, что стоит их ставить в предложениях". "Все" понимают рекламу, это "хороший стиль рекламы". Но не все понимают сложный язык литературных произведений, пользующихся всей мощью русского языка и это их хороший стиль. Отменим? Оставим только понимаемые всеми?
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 11 2008, 13:42
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(VladimirYU @ Nov 11 2008, 13:42)  Все правильно, но вот конструкция, например Код char tmp = SPSR; // tmp далее не исп.; генерит код чтения регистра а просто Код SPSR; нет. М.б. все таки "тупое" явное чтение в переменную более надежно, чем варианты предлагаемые гуру. IAR 4.12 оптимизация отключена. "оптимизация отключена" - это не то для таких проверок. При "оптимизация откулючена" компилятор вообще должен бы делать всё "строго как написано", т.е. если написано подряд десять присваиваний в какую-то (не-volatile) переменную, то все десять и написать. И для первого фрагмента даже при не-volatile SPSR мог бы и прочитать, и записать. "Благодаря" этому и прижилась такая конструкция для "гарантированного чтения" со времён компиляторов с недоразвитой оптимизацией - исправно читали не-volatile - переменную в не-volatile-переменую. По моему мнению, конструкция если и имеет право на жизнь, то только как обход ошибочно не объявленного как volatile регистра в не подлежащих изменению h-файлах. В такой форме volatile char tmp = non_volatile_var;А вот если со включенной оптимизацией для указанных выше фрагментов кода генерируется разный код, то, на мой взгляд, что-то тут не то. Цитата(VladimirYU @ Nov 11 2008, 13:42)  Может и не убедительный, но все же аргумент в пользу "тупых" конструкций. Пользуясь уже проскочившей аналогией, эта конструкция - "арго", "сленг" gcc. Использовать или нет - зависит от условий. Так же как и сленг в любой другой области - между своими повышает эффективность общения (в данном случае "между своими" - это "рассчитывая на компилятор gcc и на активно использующих его на полную катушку"). Чужим непонятно, но стоит ли ради "общепонятности" жертвовать эффективностью - решать каждый раз пишущему. Ещё раз напоминаю про ++i и i++ и указатели - то же самое, только на более низком пороге "свой-чужой", "общепонятности - не общепонятности". Бывает трудно понимается.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 11 2008, 13:43
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(aaarrr @ Nov 11 2008, 16:31)  Они там описаны как __io union, никаких volatile в помине нет. Разочарую Вас. Сорри, но не умею выделять в окошке кодов: Цитата __io Controls the storage of data objects in I/O memory space, alternatively data memory space. The __io memory attribute implies that objects are __no_init and volatile, and allows objects to be accessed by use of the special I/O instructions in the AVR microcontroller. Your application may access the AVR I/O system by using the memory-mapped internal special function registers (SFRs). To access the AVR I/O system efficiently, the __io memory attribute should be included in the code. Address range Max object size Pointer size Memory space 0-0x3F 4 bytes (32 bits) Pointers not allowed I/O 0x60-0xFF 4 bytes (32 bits) Pointers not allowed Data Table 64: I/O address ranges
|
|
|
|
|
Nov 11 2008, 13:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(aaarrr @ Nov 11 2008, 15:31)  Они там описаны как __io union, никаких volatile в помине нет. Если это так, то это ошибка того, кто эти h-файлы писал. Цитата(VladimirYU @ Nov 11 2008, 15:43)  Разочарую Вас. Сорри, но не умею выделять в окошке кодов: Ну если так... А проверьте то же самое с явно заданной Код volatile char vch; а не с SPSR. Может где-то отвалилась volatile-ность __io_memory
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 11 2008, 13:46
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(aaarrr @ Nov 11 2008, 16:31)  Они там описаны как __io union, никаких volatile в помине нет. Цитата __io Controls the storage of data objects in I/O memory space, alternatively data memory space. The __io memory attribute implies that objects are __no_init and volatile, and allows objects to be accessed by use of the special I/O instructions in the AVR microcontroller. Your application may access the AVR I/O system by using the memory-mapped internal special function registers (SFRs). To access the AVR I/O system efficiently, the __io memory attribute should be included in the code. Address range Max object size Pointer size Memory space 0-0x3F 4 bytes (32 bits) Pointers not allowed I/O 0x60-0xFF 4 bytes (32 bits) Pointers not allowed Data Table 64: I/O address ranges
|
|
|
|
|
Nov 11 2008, 13:59
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(ReAl @ Nov 11 2008, 16:46)  Может где-то отвалилась volatile-ность __io_memory Такой глюк был в версии IAR3.20C, регистры I/O оптимизатор глазом не моргнув кэшировал. Но потом в начиная с 3.20D вроде его исправили. Попробую просто с обычной переменной. Цитата 9 int main() \ main: 10 { 11 12 volatile unsigned char vol_var; 13 vol_var; 14 return 0; \ 00000000 E000 LDI R16, 0 \ 00000002 E010 LDI R17, 0 \ 00000004 9508 RET 15 } То же самое Цитата 9 int main() \ main: 10 { \ 00000000 9721 SBIW R29:R28, 1 11 12 volatile unsigned char vol_var; 13 unsigned char novol_var = vol_var; \ 00000002 8108 LD R16, Y \ 00000004 2F20 MOV R18, R16 14 return 0; \ 00000006 E000 LDI R16, 0 \ 00000008 E010 LDI R17, 0 \ 0000000A 9621 ADIW R29:R28, 1 \ 0000000C 9508 RET 15 }
|
|
|
|
|
Nov 11 2008, 14:05
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(VladimirYU @ Nov 11 2008, 16:59)  То же самое Рискну повторить вопрос aaarrr из поста №38 - у вас точно не включен режим C++?
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Nov 11 2008, 14:24
|
Местный
  
Группа: Свой
Сообщений: 426
Регистрация: 5-04-07
Из: Санкт-Петербург
Пользователь №: 26 782

|
Цитата(Сергей Борщ @ Nov 11 2008, 17:05)  Рискну повторить вопрос aaarrr из поста №38 - у вас точно не включен режим C++? Конечно, Сергей, прав В режиме С все читается нормально, был С++.
|
|
|
|
|
Nov 11 2008, 17:32
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(aaarrr @ Nov 11 2008, 14:15)  Ворнинг выдает, т.к. temp не используется после присвоения. возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall off: подозреваю, что все одиозные уязвимости и проблемы Windows вытекают из "виртуозности" кодировщиков, с которой компилятор не справляется  Цитата(ReAl @ Nov 11 2008, 16:17)  Что значит "всеми"? Совсем-совсем всеми? Вот Ваш P.S. с все поймут? Или "все, имеющие уровень образования выше некоторого порога"? И причём тут маты? Так что, на мой взгляд, тут скорее "в русском языке много разных способов посттроения предложений, однако для того, чтобы быть понятым всеми, стоит избегать сложных предложений, да и вообще - наличие запятых не ещё не означает, что стоит их ставить в предложениях". "Все" понимают рекламу, это "хороший стиль рекламы". Но не все понимают сложный язык литературных произведений, пользующихся всей мощью русского языка и это их хороший стиль. Отменим? Оставим только понимаемые всеми? а что плохого в том, чтобы быть понятым всеми? или аура "продвинутости" тает при этом? мое мнение: применение "вывертов", которые допускает синтаксис Си, используется исключительно для того, чтобы выделить себя (личность) из ряда прочих (серостей). чем проще изложен алгоритм - тем меньше шансов, что будет допущена логическая ошибка в нем, заодно меньше неоднозначностей при переносе между разными компиляторами. витиеватость кода никак не отражается на оптимальности генерируемых ассемблерных конструкций (если, конечно, эта витиеватость правильно понята компилятором), и разница между i++ и i = i + 1 не видна абсолютно. и если этот пример оправдан хотя бы экономией 2-х (!!!) символов, то применение более "накрученных" штучек мало того что затрудняет восприятие кода другими, но еще может оказаться неверно понятым компилятором... так ради чего сыр-бор?! какова конечная цель: получить всегда гарантированно однозначно воспринимаемый человеком и дающий всегда верный результат код или создать некое произведение искусства, понять которое без опытнейших искуствоведов никто не в силах, и которое транслируется одинаково далеко не во всех случаях?
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 11 2008, 17:39
|
Гуру
     
Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448

|
Цитата(ARV @ Nov 11 2008, 20:18)  возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall Степень нормальная и ворнинг вполне уместный. Цитата(ARV @ Nov 11 2008, 20:18)  off: подозреваю, что все одиозные уязвимости и проблемы Windows вытекают из "виртуозности" кодировщиков, с которой компилятор не справляется  Да, очень легко хаять программистов Майкрософт. А проблемы-то как раз и начинаются с подавления сообщений компилятора. Цитата(ARV @ Nov 11 2008, 20:32)  так ради чего сыр-бор?! какова конечная цель: получить всегда гарантированно однозначно воспринимаемый человеком и дающий всегда верный результат код или создать некое произведение искусства, понять которое без опытнейших искуствоведов никто не в силах, и которое транслируется одинаково далеко не во всех случаях? Цель - не получить сотню-другую "левых" ворнингов при сборке проекта, среди которых так легко теряются "нужные".
|
|
|
|
|
Nov 11 2008, 18:53
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ARV @ Nov 11 2008, 19:32)  возможно, степень выдачи ворнингов - параноидальная? как мне кажется, это настраивается... WinAVR не выдает ничего с опцией -Wall -Wall -Wextra, без --pedantic, хотя иногда стоит и его включать. Цитата(ARV @ Nov 11 2008, 19:32)  а что плохого в том, чтобы быть понятым всеми? или аура "продвинутости" тает при этом? мое мнение: применение "вывертов", которые допускает синтаксис Си, используется исключительно для того, чтобы выделить себя (личность) из ряда прочих (серостей). Ну вот, то про маты что-то, то про ауру и выделение личности из серостей... "у кого что болит, тот о том и говорит"? Написать присваивание какой-то переменной там, где оно не нужно и для переменной, которая больше нигде не используется, или if(UDR); там, где не нужно ничего проверять и рисовать для этого пустое тело if - это не "выверт", это "простое изложение алгоритма"? Как на мой взгляд, так это как раз выверт для того, чтобы компилятор допёр до того, что надо всё же прочесть. Приблизительно как FUNC(VAR + 0) в фортране - тоже был некий выверт для обхода неких особенностей. Но дело в том, что если он не читает просто volatile_var; , то кто гарантирует, что при следующем витке развития он будет продолжать читать if(volatile_var); или temp = volatile_var; ? Уповать на конкретную особенность конкретного оптимизатора конкретного компилятора - это "тем меньше шансов, что будет ошибка" ? Да тут не между разными компиляторами, а между разными версиями одного компилятора или даже между разными ключами одной версии может переносимости не быть! Код var; // это просто выражение var+1; // тоже просто выражение temp = var; // это присваивающее выражение Все "выражения" (expression) должны быть абстрактной машиной "вычислены" или "оценены" (evaluate) Цитата 5.1.2.3 Program execution 1 The semantic descriptions in this International Standard describe the behavior of an abstract machine in which issues of optimization are irrelevant. 2 Accessing a volatile object, modifying an object, modifying a file, or calling a function that does any of those operations are all side effects,11) which are changes in the state of the execution environment. Evaluation of an expression may produce side effects. At certain specified points in the execution sequence called sequence points, all side effects of previous evaluations shall be complete and no side effects of subsequent evaluations shall have taken place. (A summary of the sequence points is given in annex C.) 3 In the abstract machine, all expressions are evaluated as specified by the semantics. An actual implementation need not evaluate part of an expression if it can deduce that its value is not used and that no needed side effects are produced (including any caused by calling a function or accessing a volatile object). Так вот первые два выражения в примере выше тоже должны быть "evaluated", как и третье. И если в третьем переменная temp в этом файле нигде больше не используется и не глобальная (глобальность тоже может не помочь, кстати) и var не volatile, то компилятор имеет полное право выбросить его полностью - это не нарушит "observable behavior". Повторюсь - когда-то давно не выбрасывал и во многих программах работы с аппаратурой вместо описания регистров ка volatile просто делали такое присваивание для принудительного чтения, и тянется жто до сих пор. Но это довольно быстро перестало помогать, как кстати и jmp на следующий адрес для задержки при обращении к медленным портам на PC.А если var квалифицирована как volatile, то компилятор обязан зачитать её и в первом случае. Во втором может иметь добрую волю выдать предупреждение, что результат вычисления var+1; нигде не используется, так же как и в третьем имеет право поворчать, что результат присвоения temp нигде не используется и выбросить запись в temp (но при этом обязан прочесть из var). Поэтому я и говорю, что выверты с присвоением специально для этого заведёной переменной или if с пустым телом можно рассматривать только как обход ненормальности конкретного компилятора (либо, см. выше, докажите мне это со ссылкой на стандарт и я поменяю мнение), а не как хорошую практику программирования. p.s. По крайней мере в случае С. Надо разобраться, что там с С++ - мне казалось, что базоыве вещи должны были остаться и там, иначе нет той совместимости, которая декларировалась.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 11 2008, 20:02
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
гм... я и не говорил, что пустой if - это норма... я как раз придерживаюсь противоположного мнения... а вот присваивание временной переменной с моей точки зрения - вполне нормальная практика, логичная и не нарушающая никакие стандартны-нормы-правила. volatile тут совсем ни при чем - этот модификатор никто не отменял и его значение (и назначение) не оспаривается.
на счет "специально заведенных переменных"... на сколько я понимаю, при определенном напряжении сил можно очень сложные выражения (например, нечто типа БПФ) уместить в единственном операторе, избежав "лишних" переменных (обычно они называются локальными)... и, хотя с точки зрения результата это будет совершенно верное "выражение", назвать его удобочитаемым будет можно вряд ли. скорее всего и по объему результирующего кода результат не будет отличаться от "развернутого" варианта...
практика заведения "лишних" переменных лишь для того, чтобы алгоритм вырисовывался четко и ясно с моей точки зрения вполне разумна и оправдана. а компилятор пускай соптимизирует явную избыточность - на то он и компилятор. кстати, весьма оправдан и подход, когда даже небольшие кусочки алгоритма оформляются отдельными функциями - лишь бы наглядность кода была на должном уровне.
можно сколько угодно рассуждать о том, что компилятор "должен сделать", если встретит просто упоминание переменной, но ведь если записать чуть иначе - пропадет сам предмет спора, ибо поведение компилятора станет очевидно на 100%.
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 11 2008, 22:04
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Если Вам приятно в таком духе - продолжайте, утрируйте, доходите до нелепиц и спорьте с ними - но без меня. Я вижу разницу между промежуточными переменными для разбивки сложных выражений на более простые и лишними переменными, в которые пишется для того, чтобы никогда из них не читать и этой записью ничего в окружении программы не менять (так как сама эта лишняя переменная - и не SFR и никогда никем не читается). Если бы эта запись была необходимым или достаточным условием для чтения из переменной в правой части независимо от её volatile-ности, то в этом был бы смысл. На мой взгляд в такой записи смысла приблизительно столько же, сколько в комментарии Код for( i = 0; i < 5; ++i /* инкрементируем счётчик цикла */) { } (хотя для малознакомого с С новичка этот комментарий и повышает читаемость), так как она всего лишь косвенно, через запсиь в другую переменную, говорит "а мы эту переменную прочитали!" для того, кто этого сам не видит. Всего лишь.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 14 2008, 11:31
|

nofb
  
Группа: Свой
Сообщений: 430
Регистрация: 18-05-06
Из: Москва, Зеленоград
Пользователь №: 17 218

|
 Обсуждение напоминает обсуждение кода типа Код unsigned char a if (a == a) {a=a;} "Индийский код..." Чем не устраивает вариант с просмотром дизассемблерного варианта полученного кода? Все сразу встанет на свои места - что лучше, а что хуже..
--------------------
Это не то что вы подумали ...
|
|
|
|
|
Nov 17 2008, 15:59
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
хочу для универсализма сделать версию функции printf() для вывода строки на 7-сегментный индикатор, при этом реализация получается примерно такая: Код void printf_7led(char *format, ... ){ char st[20]; sprintf(&st, format, ???); // вот тут трабла - обозначена вопросами // далее мой код, обрабатывающий st[] } трабла такая: как передать "хвост" аргументов, полученных на входе в printf_7led непосредственно в вызываемый sprintf? P.S. Работаю с WinAVR (GCC)
Сообщение отредактировал ARV - Nov 17 2008, 16:01
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Nov 17 2008, 16:24
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Код void printf_7led(char *format, ... ){ va_list args; va_start(args, format); char st[20]; vsprintfs(st, format, args); va_end(args); Но это не совсем правильный с точки зрения avr_libc метод. правильно будет примерно так: Код int putchar_7led(int symbol, FILE *stream) { ... } FILE Display;
void main() { Display = FDEV_SETUP_STREAM(putchar_7led, NULL, _FDEV_SETUP_WRITE);
fprintf(&Display, "%s", "Hello"); for(;;); }
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 11 2008, 08:56
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(ARV @ Nov 17 2008, 19:25)  мне кажется, это хоть и красивый метод, но для 6-символьного 7-сегментного дисплея наверное слишком избыточный... просто строчку вывел - сразу понятно, что предыдущая затерлась... а при посимвольном выводе надо как-то так же красиво и логично отслеживать момент, когда строка кончилась... не находите? Ну избыточный он не этим - на шести символах просто толком негде разгуляться форматными строками с ширинами полей и т.п. А что касается "отслеживать момент" - да на раз, було бы желание покуражиться. Можно заставить по '\n' очищать строку - причём: - либо сразу по нему, тогда выводить строки вида "\nHELLO", что будет приводить к очистке и выводу, последующий вывод допишет в конец - либо по нему запоминать, что строка была завершена и уже последующий вывод очистит и начнёт с начала строки, тогда выводить (&Display, "Err %02X\n", err_code); Во втором случае в putchar_7led заводится статический флаг, который запоминает прохождение '\n' Код int putchar_7led(int symbol, FILE *stream) { static bool newline = true; if( symbol == '\n') { newline = true; } else { if( newline ) { // прочистить пробелами весь индикатор и поставить указатель символа // на начало буфера динамической индикации } newline = false; // вывести символ в текущую позицию } }
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Dec 12 2008, 07:09
|

Профессионал
    
Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581

|
Цитата(ReAl @ Dec 11 2008, 11:56)  Ну избыточный он не этим - на шести символах просто толком негде разгуляться форматными строками с ширинами полей и т.п. А что касается "отслеживать момент" - да на раз, було бы желание покуражиться. как раз желания куражиться и не было. я поступил по первому совету - сделал оберточные функции для sprintf с преобразованием нормальных символов в семисегментные и весьма доволен результатом. на верхнем уровне и для семисегментника пишу printf_7led("%.2u", var) - и все выводится  а когда надо, то и так работает printf_7led("stop"). жаль, не все буквы в семисегментные варианты преобразуются  особенно кириллица - слишкам многа букафф
--------------------
Я бы взял частями... но мне надо сразу.
|
|
|
|
|
Dec 25 2008, 00:06
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(ARV @ Nov 11 2008, 22:02)  практика заведения "лишних" переменных лишь для того, чтобы алгоритм вырисовывался четко и ясно с моей точки зрения вполне разумна и оправдана. а компилятор пускай соптимизирует явную избыточность - на то он и компилятор. кстати, весьма оправдан и подход, когда даже небольшие кусочки алгоритма оформляются отдельными функциями - лишь бы наглядность кода была на должном уровне. Для того чтобы алгоритм вырисовывался "четко и ясно", на мой взгляд больше подходит другая практика. Во-первых избегать появления дурного кода - т.е. сводить в минимуму потребность в таких вот "var;" и лишних переменных. С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе! Или почему SPSR надо обязательно читать в никуда? Можно же хотя бы в целях статистики хранить последнее значение SPSR: Код ISR() { ... spiContext.LastSpsrVal = SPSR; } производительности-то оно не сожрет. во-вторых - применять практику самодокументируемого кода - завести однозначно понятные макросы: Код #define access( x ) // обращение к X #define ignore( x ) // игнорировать x ... Встретив в коде Код access( SPSR ); Даже те "кто в танке" сразу поймут, что делается с SPSR. А столкнувшись с "финтом" компилятора - достаточно поменять только тело макроса...
|
|
|
|
|
Dec 25 2008, 08:21
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(defunct @ Dec 25 2008, 03:06)  С какого бодуна драйвер решил вдруг опустошить содержимое буферов? Ведь можно построить драйвер так, что тупое опустошение не понадобится вовсе! Научите  у LPC2000 за тем-же SPI есть FIFO которое - не отключается - нет возможности сбросить его Как сделать запись по SPI так, что-бы когда-нибудь при чтении можно было прочтать SPI, а не содержимое забитого при записи FIFO. Цитата Или почему SPSR надо обязательно читать в никуда? Можно же хотя бы в целях статистики хранить последнее значение SPSR: Потому, что там содержится "ничто" которое отлично отправляется в "никуда". Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt при этом необходимость комментариев это мелочь, а вот умозрительный подбор расходной регистровой переменной не радует. Цитата spiContext.LastSpsrVal = SPSR; производительности-то оно не сожрет. Да? Вместо, например, команды чтения в первый попавшийся расходный регистр будет производится считывание (для load/store через тот-же промежуточный регистр) в структуру находяшуюся в памяти..... Цитата Даже те "кто в танке" сразу поймут, что делается с SPSR. Угу, приходишь в магазин, а там на бутылке с маслом надпись масло(масло); Начинаешь думать, а чего это вдруг так написали - может смысл какой есть? Смотришь header спрашиваешь и тебе объясняют,что это масло для танкистов....  . В общем-то конечно можно макрос написать, но лишняя сущность.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 25 2008, 11:19
|

читатель даташитов
   
Группа: Свой
Сообщений: 853
Регистрация: 5-11-06
Из: Днепропетровск
Пользователь №: 21 999

|
Цитата(zltigo @ Dec 25 2008, 10:21)  Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt А почему не так: Код VICVectAddr = 0; Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант...
|
|
|
|
|
Dec 25 2008, 11:42
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(HARMHARM @ Dec 25 2008, 14:19)  Код VICVectAddr = 0; Чтобы избежать лишнего обращения к константе? По-идее будет взята из генератора констант... Полноразмерная Константа будет взята из памяти, или сгенерирована в регистре, но все это уже громоздко по сравнению с минималистичной записью первого попавшегося регистра c произвольным значением. По этой причине и указываю имя некой "недалеко" находящейся переменной.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 25 2008, 13:29
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(zltigo @ Dec 25 2008, 10:21)  Научите  у LPC2000 за тем-же SPI есть FIFO которое - не отключается - нет возможности сбросить его Как сделать запись по SPI так, что-бы когда-нибудь при чтении можно было прочтать SPI, а не содержимое забитого при записи FIFO. Думаю, счетчик отправленных байт должен помочь. Драйвер будет вытаскивать из FIFO ровно то количество байт, которое он запихнул при записи. Цитата Я бы не отказался и от обратной возможности - записи "ничего", а то бывает приходится писать, например, Код VICVectAddr = i; // Dummy write to signal end of interrupt при этом необходимость комментариев это мелочь, а вот умозрительный подбор расходной регистровой переменной не радует. Можно дать константу (опять же если производительности хватает). VICVectAddr = 0; или VICVectAddr = CurrentVector; будет чуть-чуть дольше, зато интуитивно понятно, что делается. Цитата Да? Вместо, например, команды чтения в первый попавшийся расходный регистр будет производится считывание (для load/store через тот-же промежуточный регистр) в структуру находяшуюся в памяти..... Да, тут сознательно добавляем запись в память. Медленнее чем в регистр - да, сильно скажется на производительности всей системы - нет! (всего лишь запись одной ячейки на FIFO циклов SPI). Польза от этой записи - когда свалимся в DABT, можно будет снять дамп и посмотреть состояние железа, в т.ч. и значение SPSR (вдруг именно его значение поможет найти причину аборта). Я говорю не отказаться, а свести к минимуму потребность в пустых чтениях, пустых переменных, и прочем дурном коде, и чтобы не быть пустословным показываю как можно этого добиться. А выбор делать так или нет - как всегда за разработчиком. Цитата(zltigo @ Dec 25 2008, 10:21)  Угу, приходишь в магазин, а там на бутылке с маслом надпись масло(масло);  Ну всяко лучше так, чем взять банку с желтым содержимым без надписи и понять что это совсем не масло, когда содержимое уже плеснули на сковородку.  Цитата В общем-то конечно можно макрос написать, но лишняя сущность. Дело привычки. Например как Вы поступите если есть некий шаблон колбека: Код typedef void (*putmsg_cb)(char *, int, int) и куча функций подпадающих под этот шаблон, но не использующих все параметры? Мне удобно поступать так: Код void xx_putmsg( char *msg, int size, int priority) { ignore( priority ); // <-- избавились от warning'a и сразу видно, что параметр priority нафиг не нужен ... }
|
|
|
|
|
Dec 25 2008, 14:06
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(defunct @ Dec 25 2008, 16:29)  Думаю, счетчик отправленных байт должен помочь. Драйвер будет вытаскивать из FIFO ровно то количество байт, которое он запихнул при записи. Вопрос ведь в том, КУДА ОН ИХ БУДЕТ ДЕВАТЬ после ВЫТАСКИВАНИЯ? Выбрасывать? Вы обещали научить меня писать драйвера Цитата .... так, что тупое опустошение не понадобится вовсе! Если под "умным" опустошением предполагается их, при их априори полной бесполезности тем не менее складывать куда-то дабы "когда свалимся в DABT, можно будет снять дамп и посмотреть", то что тогда назвать безумием Цитата будет чуть-чуть дольше, зато интуитивно понятно, что делается. И дольше и уж абсолютно интуитивно не понятна запись совершенно конкретного нуля, когда на самом деле может быть записано абсолютно произвольное значение  . В общем это,конечно, мелочи... Но лучше владеть языком так, дабы не было и мелких огрехов, а не уповать на то, что "твоя моя и так понимай если твоя моя понимай однако нада будет". Цитата(defunct @ Dec 25 2008, 16:29)  Дело привычки. Например как Вы поступите если есть некий шаблон колбека: Код typedef void (*putmsg_cb)(char *, int, int) и куча функций подпадающих под этот шаблон, но не использующих все параметры? Мне удобно поступать так: Код void xx_putmsg( char *msg, int size, int priority) { ignore( priority ); // <-- избавились от warning'a и сразу видно, что параметр priority нафиг не Будете смеяться, но мне - удобно АБСОЛЮТНО аналогично  . Код #define argsused(foo) (void)(foo) argsused( priority ); Только это совсем разные случаи, ибо в описываемый ранее SPSR; Абсолютно самодостаточен и не совершенно не нуждается, в отличии от priority, ни в каких мусорных обертках ignore( SPSR ); Если хотите сделать понятным для "танкистов", то напишите комментарий - "танкист" чуть-чуть выглянет из люка и узнает немного нового
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Dec 25 2008, 15:32
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(zltigo @ Dec 25 2008, 16:06)  Вопрос ведь в том, КУДА ОН ИХ БУДЕТ ДЕВАТЬ после ВЫТАСКИВАНИЯ? Выбрасывать? Складывать в кольцевой буфер, и "семафорить - данные есть". Если эти данные хоть кому-то нужны, обрабатывающий процесс их заберет, если не нужны драйвер перетрет их нафиг по кольцу. Но взятки - гладки, свою работу - принять, нативно опустошить, просигналить - драйвер сделал. Цитата Вы обещали научить меня писать драйвера Это перебор. Я такого не обещал, к тому же Вы и так умеете их писать. А порассуждать как можно написать драйвер, чтобы избежать пустых чтений - это пожалуйста.  Цитата Если под "умным" опустошением предполагается их, при их априори полной бесполезности тем не менее складывать куда-то дабы "когда свалимся в DABT, можно будет снять дамп и посмотреть", то что тогда назвать безумием  Под "умным" опустошением понимаем - монотонную работу драйвера. Не ему решать что полезно, а что бесполезно. Принимать без разбора драйвер должен абсолютно все, что физически приходит, и отдавать upper layer'у на рассмотрение. Цитата Но лучше владеть языком так, дабы не было и мелких огрехов, а не уповать на то, что "твоя моя и так понимай если твоя моя понимай однако нада будет". Бесспорно. Но, даже при хорошем владении языком, лучше уходить от неоднозначностей там где можно, а там где нет неоднозначностей - подчеркивать логику работы кода: if (a || b && c) или if (a || (b && c) ) вроде одно и то же, но второе ведь наглядней. Цитата Будете смеяться, но мне - удобно АБСОЛЮТНО аналогично  . Смеяться не буду, - хорошо, что мы на одной волне в этом вопросе  Цитата Только это совсем разные случаи, ибо в описываемый ранее SPSR; Абсолютно самодостаточен и не совершенно не нуждается, в отличии от priority Я бы не был так категоричен. Потому что SPSR - это не переменная, а макрос. Что там за ним спрятано - хз. Скажете, а UM на что, а если его нет под рукой у читателя кода? Цитата ни в каких мусорных обертках ignore( SPSR ); Если хотите сделать понятным для "танкистов", то напишите комментарий - "танкист" чуть-чуть выглянет из люка и узнает немного нового  шутку понял Но все же argused() ignore() accessed() и т.п. делают код прозрачнее, и гибче при переносе.
|
|
|
|
|
Dec 25 2008, 16:09
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(defunct @ Dec 25 2008, 17:32)  if (a || b && c) или if (a || (b && c) ) вроде одно и то же, но второе ведь наглядней. Это далеко не одно и то же. Логические операции И и ИЛИ всегда выполняются слева направо. Даже компилятор не имеет права изменить этот порядок. Эквивалентным будет if (( a || b ) && c) и со скобками действительно нагляднее.
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
Dec 25 2008, 16:24
|

кекс
     
Группа: Свой
Сообщений: 3 825
Регистрация: 17-12-05
Из: Киев
Пользователь №: 12 326

|
Цитата(Сергей Борщ @ Dec 25 2008, 18:09)  Это далеко не одно и то же. Логические операции И и ИЛИ всегда выполняются слева направо. Даже компилятор не имеет права изменить этот порядок. Эквивалентным будет if (( a || b ) && c) и со скобками действительно нагляднее. А приоритеты операций? Все-таки if (a || b && c) или if (a || (b && c) ) это одно и то же. Если есть время, просимулируйте вот этот тестик: Код void test(void) { int a = 1; int b = 0; int c = 0;
if (a || b && c ) printf("1 || (0 && 0)"); else printf("(1 || 0) && 0"); } У меня результат этого теста - "1 || (0 && 0)". (RVDS 2.2 и 3.1).
|
|
|
|
|
Jan 4 2009, 11:12
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(zltigo @ Oct 20 2008, 20:17)  Поскольку регистры uart безвариантно являются и прописаны как volatile, то несомнено второй вариант, ибо явные промежуточные переменные просто совсем не нужны. Что-то не получается обойтись без временной переменной. Вот код: Код void i2cStartRead(dword address) { ... //dword temp = I2C2->SR2; I2C2->SR2; } на что компилер (RV) ругается: i2c.cpp(71): warning: #174-D: expression has no effect Тот же самый код разложенный по "полочкам": Код typedef volatile unsigned short vu16; typedef unsigned short u16;
typedef struct { vu16 CR1; u16 RESERVED0; vu16 CR2; u16 RESERVED1; vu16 OAR1; u16 RESERVED2; vu16 OAR2; u16 RESERVED3; vu16 DR; u16 RESERVED4; vu16 SR1; u16 RESERVED5; vu16 SR2; u16 RESERVED6; vu16 CCR; u16 RESERVED7; vu16 TRISE; u16 RESERVED8; } I2C_TypeDef;
void i2cStartRead(dword address) { ... ((I2C_TypeDef *) (((u32)0x40000000) + 0x5800))->SR2; } Как убрать предупреждение компилятора, и обойтись без явной временной переменной?
|
|
|
|
|
Jan 4 2009, 14:31
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(sonycman @ Jan 4 2009, 14:12)  Как убрать предупреждение компилятора, и обойтись без явной временной переменной? Что-то я совсем не понял, что и как Вы собственно написали  . А вообще так: Код typedef volatile struct { unsigned short SR2; ..... } I2C_TypeDef;
I2C_TypeDef *I2C2 = (I2C_TypeDef *)(0x40000000 + 0x5800);
void i2cStartRead(void) { .... I2C2->SR2;
} P.S. И вместо мути в структуре ввиде 'reserved' используйте 32bit паковку.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 4 2009, 15:42
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
Цитата(zltigo @ Jan 4 2009, 18:31)  Что-то я совсем не понял, что и как Вы собственно написали  . А вообще так... P.S. И вместо мути в структуре ввиде 'reserved' используйте 32bit паковку. Так эта муть - библиотека ST для STM32. Я из неё использую только определения регистров. Ну её нафиг переделывать, и так пришлось править, чтобы хидеры из C++ компилировались... Попробовал, как Вы подсказали: Код typedef volatile struct { int a; int b; unsigned short SR2;
} I2C_Type_Def; I2C_Type_Def * I2C2_1 = (I2C_Type_Def *)(0x40000000 + 0x5800);
I2C2_1->SR2; но компилятор по-прежнему ругается: main.cpp(26): warning: #174-D: expression has no effect и выкидывает из кода эту строку...
|
|
|
|
|
Jan 4 2009, 16:22
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(sonycman @ Jan 4 2009, 21:42)  Попробовал, как Вы подсказали: Код typedef volatile struct { int a; int b; unsigned short SR2;
} I2C_Type_Def; I2C_Type_Def * I2C2_1 = (I2C_Type_Def *)(0x40000000 + 0x5800);
I2C2_1->SR2; но компилятор по-прежнему ругается: main.cpp(26): warning: #174-D: expression has no effect и выкидывает из кода эту строку...  Впервые вижу волатильную структуру  Может я ошибаюсь, но только переменная может иметь этот атрибут. Попробуйте объявить так: Код (volatile I2C_Type_Def *)(0x40000000 + 0x5800)->SR2; Потом проверьте есть ли в листинге чтение этого регистра. Я написал без временной переменной, но если она нужна или надо делать несколько чтений, то можно так: Код volatile I2C_Type_Def * I2C2_1 = (volatile I2C_Type_Def *)(0x40000000 + 0x5800);
I2C2_1->SR2;
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 4 2009, 16:27
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(GetSmart @ Jan 4 2009, 19:22)  но только переменная может иметь этот атрибут... С чего-бы это вдруг, тем более, что сами написали volatile I2C_Type_Def * I2C2_1 А если хотели I2C_Type_Def * volatile I2C2_1 так это совсем другое....
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 4 2009, 17:05
|
.
     
Группа: Участник
Сообщений: 4 005
Регистрация: 3-05-06
Из: Россия
Пользователь №: 16 753

|
Цитата(zltigo @ Jan 4 2009, 22:27)  С чего-бы это вдруг, тем более, что сами написали volatile I2C_Type_Def * I2C2_1 А если хотели I2C_Type_Def * volatile I2C2_1 так это совсем другое.... Не, не. Я правильно выразил свою мысль в коде  <<volatile I2C_Type_Def *>> говорит, что там, по адресу будет лежать волатильная структура/переменная. Переменная с адресом (I2C2_1) не должна/обязана быть волатильной. Разглядывая чужие хидеры, например из ИАРа, я ни разу не встречал волатил при объявлении структур, а вот при объявлении переменных - всегда. Поэтому и удивился. Если, теоретически, структуры могут иметь этот атрибут, то возможно проблема у sonycman-а в том, что компилятор не учитывает волатил из структуры, но будет учитывать при непосредственном объявлении в переменной. Проверить-то легко.
--------------------
Заблуждаться - Ваше законное право :-)
|
|
|
|
|
Jan 4 2009, 17:49
|

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(GetSmart @ Jan 4 2009, 20:05)  то возможно проблема у sonycman-а в том... Проблема в том, что компилятор плюсовый. Цитата(GetSmart @ Jan 4 2009, 20:05)  <<volatile I2C_Type_Def *>> говорит, что там, по адресу будет лежать волатильная структура... Угу, только почему-то буквально строчкой выше Вы выражали сомнение в возможности описания таких структур  . О чем речь я и завел.
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Jan 4 2009, 18:30
|

Любитель
    
Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695

|
В оригинальной библиотеке для STM32 квалификатор volatile стоит у каждого члена структуры: Код typedef volatile unsigned short vu16; typedef unsigned short u16;
typedef struct { vu16 CR1; u16 RESERVED0; vu16 CR2; u16 RESERVED1; vu16 OAR1; u16 RESERVED2; vu16 OAR2; u16 RESERVED3; vu16 DR; u16 RESERVED4; vu16 SR1; u16 RESERVED5; vu16 SR2; u16 RESERVED6; vu16 CCR; u16 RESERVED7; vu16 TRISE; u16 RESERVED8; } I2C_TypeDef; По совету zltigo я попробовал с квалификатором перед всей структурой: Код typedef volatile struct { unsigned short SR2; } I2C_Type_Def; Но, к сожалению, разницы нет. Такая прикольная конструкция: Код (void)I2C2_1->SR2; действительно молча проглатывается - нет ни предупреждения, ни кода... В общем, буду знать, что C++ не допускает выражений, подобных ... variable_name_only;...
|
|
|
|
|
Jan 4 2009, 19:00
|

Гуру
     
Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095

|
Цитата(GetSmart @ Jan 4 2009, 19:05)  Если, теоретически, структуры могут иметь этот атрибут, Конечно могут, как и любые другие типы данных. Применение модификатора volatile (также как и const) к структуре распространяет его на все члены структуры. Цитата(zltigo @ Jan 4 2009, 19:49)  Проблема в том, что компилятор плюсовый. Точнее это бага плюсового компилятора. Я все-таки залез в стандарт С++, и вот что он пишет: Цитата 1.9 Program execution 6. The observable behavior of the abstract machine is its sequence of reads and writes to volatile data and calls to library I/O functions. 7. Accessing an object designated by a volatile lvalue (3.10), modifying an object, calling a library I/O function, or calling a function that does any of those operations are all side effects, which are changes in the state of the execution environment. [...] 7.1.5.1 The cv-qualifiers 8. [Note: volatile is a hint to the implementation to avoid aggressive optimization involving the object because the value of the object might be changed by means undetectable by an implementation. See 1.9 for detailed semantics. In general, the semantics of volatile are intended to be the same in C++ as they are in C. ]
--------------------
На любой вопрос даю любой ответ"Write code that is guaranteed to work, not code that doesn’t seem to break" ( C++ FAQ)
|
|
|
|
|
  |
4 чел. читают эту тему (гостей: 4, скрытых пользователей: 0)
Пользователей: 0
|
|
|