Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос к знатокам С.
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2
demiurg_spb
Возник тут вопрос.
Кусочек программы можно написать двумя способами,
но с одним и тем же правильным результатом (компилятор 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;
zltigo
Цитата(demiurg_spb @ Oct 20 2008, 18:04) *
Вопрос: это можно взять на вооружение?

Поскольку регистры uart безвариантно являются и прописаны как volatile, то несомнено второй вариант, ибо явные промежуточные переменные просто совсем не нужны.
scifi
Спасибо за подсказку.
Я, по незнанию, наверное, всегда делал присвоение промежуточной переменной. Что-то подсказывает, что второй вариант тоже законный, но тщательное чтение стандарта C99 не помогло выявить пункт, который это подтверждает. Не могли бы более знающие товарищи навести на этот пункт (пункты)?
С другой стороны, присваивание промежуточной переменной имеет одно преимущество: даже неискушённые в глубоких тонкостях языка Си поймут, что имелось в виду. На мой взгляд, это сильное преимущество. Не следует жертвовать читаемостью кода.
demiurg_spb
Цитата(scifi @ Oct 20 2008, 21:27) *
Спасибо за подсказку.

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

На мой взгляд читаемость лишь улучшается.
А вот первоисточник сего финта найти надо, да как вообще это называется очень хочется узнать, чтоб знать хоть что искать.
zltigo
Цитата(scifi @ Oct 20 2008, 19:27) *
...но тщательное чтение стандарта C99 не помогло выявить пункт, который это подтверждает.

Кроме прочитать, нужно еще и суть понимать.
1.Упоминание имени переменной означает обращение к ней. Это основы основ. Какие "подтверждения" еще требуются?
2.Для того, что бы "бесполезные" обращения не были выкинуты компилятором есть клбчевое слово volatile. Поиск по доукменту, надеюсь работает?
Цитата
С другой стороны, присваивание промежуточной переменной имеет одно преимущество: даже неискушённые в глубоких тонкостях языка Си поймут, что имелось в виду. На мой взгляд, это сильное преимущество. Не следует жертвовать читаемостью кода.

Вcе с точностью до наоборот sad.gif
1. Никаких "тонкостей" нет напрочь - это самые основы.
2. Введение неких ненужных переменных, получение воплей о их ненужности от компилятора, закрытие этих вопплей - да какая уж тут, простите, в результате "читаемость"!?
Цитата
А вот первоисточник сего финта найти надо,

"Финты" это как-раз с лишней переменной sad.gif не знаю, какой "умник" такой финт и с какого бодуна применил, но думаю, что его уже не найти smile.gif
scifi
Цитата(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.
Действительно, есть значение выражения, а для его получения необходимо обращение к полю сруктуры.
zltigo
Цитата(scifi @ Oct 20 2008, 20:35) *
Контрпример: взятие адреса переменной. Имя упоминается, а обращения нет.

На то это и ДРУГАЯ ОПЕРАЦИЯ. Совсем другая - взятие адреса, а не значения.
Цитата
После...

Эко куда Вас понесло..... Зачем?
scifi
Цитата(zltigo @ Oct 20 2008, 22:17) *
1.Упоминание имени переменной означает обращение к ней.

Цитата(zltigo @ Oct 20 2008, 23:11) *
На то это и ДРУГАЯ ОПЕРАЦИЯ. Совсем другая - взятие адреса, а не значения.

Я запутался... Взятие адреса - это совсем другая операция по сравнению с упоминанием имени переменной? То есть "var++" - это упоминание имени, а "&var" - нет?

Цитата(zltigo @ Oct 20 2008, 23:11) *
Эко куда Вас понесло..... Зачем?

Затем, что вопрошающий сказал: "И что стандарт может нам сказать по этому поводу?" Посему стараюсь приводить цитаты из стандарта, имеющие отношение к данному вопросу.
demiurg_spb
Цитата(scifi @ Oct 20 2008, 23:34) *
Я запутался... Взятие адреса - это совсем другая операция по сравнению с упоминанием имени переменной? То есть "var++" - это упоминание имени, а "&var" - нет?

Если раскрутить, то получим такую цепочку:
var++;
var += 1;
var = var + 1;

Отсюда видно, что что тут происходит не только упоминание переменной всуеsmile.gif
А взятие адреса - это действие, которое никак не отражается на самой переменной -
происходит лишь загрузка в индексный регистр адреса переменной.
sergeeff
Цитата(zltigo @ Oct 20 2008, 20:17) *
Поскольку регистры uart безвариантно являются и прописаны как volatile, то несомнено второй вариант, ибо явные промежуточные переменные просто совсем не нужны.



К примеру MSVS 2008 для ARM в обоих случаях генерит одинаковый код.
zltigo
Цитата(demiurg_spb @ Oct 20 2008, 21:53) *
А взятие адреса - это действие, которое никак не отражается на самой переменной -
происходит лишь загрузка в индексный регистр адреса переменной.

Есть еще и другие операции, например декларирование, sizeof, ...
Цитата
Посему стараюсь приводить цитаты из стандарта, имеющие отношение к данному вопросу.

Ну не обязан стандарт заменять учебник арифметики.
Пишем:
a = b
проговариваем как первоклашки на уроке арифметики - "взяли значение переменной 'b' и присвоили его переменной 'a'"
Теперь пишем:
b
проговариваем - "взяли значение переменной 'b'". И... и все. Все, что нам надо, мы сделали! Ничего лишнего и мутного. Чего не понятно-то? Какие какие такие "тонкости C"?


Цитата(sergeeff @ Oct 21 2008, 17:08) *
К примеру MSVS 2008 для ARM в обоих случаях генерит одинаковый код.

Ну и что? Слава оптимизации! Сначала читатель продирается через нагрможденение ненужностей, потом компилятор. Если оба поняли, что все эти "финты" не нужны совсем, то результаты, етественно будут одинаковые - БЕЗ ФИНТОВ.
sergeeff
Без финтов - это отлично, но!!! - очень непривычно. Чтение из переменной очевидно, когда оно стоит справа от знака присваивания. И когда этот знак опущен это и вызывает недоумение и неприятие.

Я думаю, если бы разместить где-нибудь на форумах вопрос типа: "Что означает выражение для переменной volatile int x?: x;"

абсолютное большинство ответит неправильно. Посему, учитывая, что всех не переучишь, и почти все люди работают в коллективах, я бы именно из этих соображений оставил бы: int temp = x;.

Коллеге zltigo респект за неординарный подход. Тем более, что почти аналогичное использование чтения переменной, например, в while(x) ни у кого вопросов не вызвало бы.
aaarrr
Цитата(sergeeff @ Oct 21 2008, 21:01) *
Коллеге zltigo респект за неординарный подход.

Это единственно верный подход. Или предпочитаете ворнинги давить всем коллективом?
scifi
Итак, итоги:
1) Согласно стандарту языка для чтения volatile переменной var достаточно написать
Код
var;

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


Итак, задача сведена к спору "читаемость кода против подавления предупреждений компилятора". Как известно, такой спор заведомо неразрешим, так что дальнейшие дискуссии результата не принесут :-)
zltigo
Цитата(scifi @ Oct 21 2008, 19:42) *
Другими словами, читаемость кода страдает.

Это утверждение абсолютно ложное sad.gif, посему и "вывод" такой-же.
Код
var; // Это читабельно

А что-то типа такого, даже максимально обвешенного для понимания ненужности "финтов":
Код
{
int tmp = var;
tmp = tmp;
}  // Много, много хуже.

А такое:
Код
tmp = var; // Вообще безобразие
Сергей Борщ
Цитата(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;
zltigo
Цитата(Сергей Борщ @ Oct 21 2008, 22:38) *
Очень интересно. ИАР для АРМов, версии 4.30 точно (более старшие не проверял), с легкостью выкидывает такие обращения.

Любой вменяемый компилятор выкидывает, но ЕСЛИ НЕ volatile. В данном случае это volatile, а не для volatile - выкидывает правильнно, ибо пустое и бессмысленное действие.
Цитата
ReAl объяснил это мутностью стандарта в этой части.

Никакой мутности в отношении volatile переменных в C99 нет.
Сергей Борщ
Цитата(zltigo @ Oct 21 2008, 23:42) *
Любой вменяемый компилятор выкидывает, но ЕСЛИ НЕ volatile.
Вот сейчас специально поставлю ИАР и приведу листинг. Именно volatile переменную. Момент...
zltigo
Цитата(Сергей Борщ @ Oct 21 2008, 22:38) *
Все встречавшиеся мне компиляторы убирали предупреждение при добавлении строчки dummy = dummy;

Наиблее часто встречающийся sad.gif с "финтами", но безграмотный вариант sad.gif. Однозначный и независимый от компилятора и опимизации:
Код
(void)dummy;

Цитата(Сергей Борщ @ Oct 21 2008, 22:46) *
Вот сейчас специально поставлю ИАР и приведу листинг. Именно volatile переменную. Момент...

Не стоит smile.gif. Не получится.
Сергей Борщ
Цитата(zltigo @ Oct 21 2008, 23:51) *
Не стоит smile.gif. Не получится.
Если бы не получалось, я бы в эту ветку не писал:


Пожалуйста:
Код
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

Поэтому и хочется увидеть цитату из стандарта. А самому искать лень wink.gif GCC даже в версии 3.2.3 от 2003(?) года не выкидывает.
zltigo
Цитата(Сергей Борщ @ 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 будет тоже самое. Ибо вариантов нет.
demiurg_spb
Попробовал на древнем:
Цитата
# 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
Сергей Борщ
Цитата(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 изменился smile.gif

Все, спать. Иначе придется самим в стандарте копаться wink.gif
zltigo
Цитата(Сергей Борщ @ Oct 21 2008, 23:38) *
ИАР вполне себе сишный компилятор и....

Тем не менее, ты компилишь П Л Ю С О В Ы М (точнее недоплюсовым sad.gif ) компилятором, почему-то рассуждая о C99. Кроме того, ты получил более, чем вменяемый Warning.
Цитата(Сергей Борщ @ Oct 21 2008, 23:38) *
...но, как видим, не всегда работает

Я бы поверил, в баг конкретного компилятора, если-бы не работал и с этой версией компилятора, причем гарантированно, многократно и постоянно использовал и использую, как минимум:
SSPDR;
для очистки FIFO SSP при полудуплексной передаче.
Хидеры традиционно использую самописные.
Цитата(Сергей Борщ @ Oct 21 2008, 23:38) *
По поводу типичности сообщений один человек очень красиво написал на AVRFreaks:

В данном случае я говорю о типичном собщении совершенно конкретного компилятора.
Сергей Борщ
Цитата(zltigo @ Oct 22 2008, 00:50) *
Тем не менее, ты компилишь ПЛЮСОВЫМ компилятором.
В точку. Попробовал без плюсов - варнинга нет, чтение есть. Придется штудировать и плюсовый стандарт crying.gif Не думал, что в этом вопросе он отличается от неплюсового.
zltigo
Цитата(Сергей Борщ @ Oct 21 2008, 23:55) *
Не думал, что в этом вопросе он отличается от неплюсового.

Не думаю, что отличается, поскольку это совершенно естественное-разумное поведение. Любое другое не берусь даже хоть как-то объяснить...Полубаг "старого" компилятора sad.gif ?

P.S.
Попробовал. Любая версия V4-V5 плюсовых компиляторов от IAR выдает warning. Странно.
Непомнящий Евгений
Цитата(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 smile.gif

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

UDR0 - из стандартного иаровского хидера:
...
Ворнинг давится только dummy=dummy smile.gif

PS начал читать тему - думал можно будет избавиться от этого некрасивого кода sad.gif

В Вашем случае прочитать UDR0 без dummy можно и так:
Код
    if (UDR0);

Правда не знаю насколько это читабельно смотрится. На любителя. В плюсах работает и я уже привык.
zltigo
Цитата(Непомнящий Евгений @ Oct 22 2008, 06:41) *
IAR AVR 4.3 (EEC++).....

Ну что я могу сказать - много значит cтранностей в IARовском недоплюсовом компиляторе sad.gif. Подчеркиваю еще раз ПЛЮСОВОМ, а тема начинслась как C/C99.
Если
var;
я в своих плюсовых программах использую редко, поскольку от железа они обычно далеки, то уж
(void)var;
ввиде макросика USED(var) - в процессе написания ну очень часто.
При этом С компилятор от IAR ведет себя абсолютно ожидаемо, впрочем, как и абсолютно все C используемые мной за долгие годы.
В оправдание плюсового IAR, могу сказать только то, что warnings он тем не менее генерит...
ReAl
Цитата(Сергей Борщ @ 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
Странно...
Всё-таки странно.
Может всё-же пройтись ещё по стандарту и попробовать с ними поругаться?
IgorKossak
Цитата(ReAl @ Nov 10 2008, 13:49) *
Однако считаю, что в случае отдельно стоящей volatile-переменной в духе
Код
UDR;
компилятор должен провести все действия, необходимые для вычисления выражения (в данном случае только прочесть переменую, в случае с UDR+1; - прочесть и прибавить единицу), а только потом обнаружить, что результат-то никому не нужен и начать оптимизатором "отматывать" назад ненужные действия - пока не упрётся в запрет, поставленный квалификатором volatile. Т.е. чтение volatile-переменной должно остаться. Если какой-то компилятор этого не делает (это тоже, кажется, где-то в аське обсуждалось), то надо внимательно ещё раз прочесть стандарт и попытаться поругаться.

Те же самые рассуждения можно провести и в случае
Код
if(UDR);
и результат по логике рассуждений будет тем же самым, но ошибка в случае с if не выдаётся.
VladimirYU
Код
  volatile int x;
  x ? : x;


IAR AVR 4.12 выдает ошибки
Error[Pe029]: expected an expression
Error[Pe053]: expected a ":"

Как к этому относится с учетом вышесказанного?
aaarrr
Цитата(VladimirYU @ Nov 11 2008, 13:56) *
Как к этому относится с учетом вышесказанного?

Правильно ругается: стандарт не предусматривает выбрасывания операндов из :?.

Можно написать так:
Код
  volatile int x;
  x ? 0 : x;
ARV
а, простите, разве писать читаемый всеми код - это уже признак дурного стиля программирования? по-моему, во все времена было наоборот... и на написанный без извратов код ни один компилятор не станет ругаться...
Код
uchar temp = UDR;

по-моему, понятно абсолютно всем, не вызывает ошибок и ворнингов, компилится в ту же самую единственную команду...

P.S. Имхо, то, что язык позволяет писать конструкции, с трудом поддающиеся расшифровке "простыми смертными", еще не означает, что так писать - хорошо или круто. в русском языке много матерных оборотов, однако их использование в речи все-же осуждается... равно как и арго и т.п. сленг...
aaarrr
Цитата(ARV @ Nov 11 2008, 14:13) *
Код
uchar temp = UDR;

по-моему, понятно абсолютно всем, не вызывает ошибок и ворнингов, компилится в ту же самую единственную команду...

Ворнинг выдает, т.к. temp не используется после присвоения.
Непомнящий Евгений
Цитата(VladimirYU @ Nov 11 2008, 14:56) *
Код
  volatile int x;
  x ? : x;

...
Как к этому относится с учетом вышесказанного?


Это расширение gcc: http://hubbard.engr.scu.edu/embedded/avr/d...ml#Conditionals
VladimirYU
Цитата(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) *

Спасибо a14.gif
Может и не убедительный, но все же аргумент в пользу "тупых" конструкций.
aaarrr
Цитата(VladimirYU @ Nov 11 2008, 14:42) *
Все правильно, но вот конструкция, например
Код
char tmp = SPSR; // tmp далее не исп.;

генерит код чтения регистра а просто
Код
SPSR;

нет.

Значит SPSR не volatile, или используется старый плюсовый IAR. По-моему, дискуссия пошла на второй круг.
VladimirYU
Цитата(aaarrr @ Nov 11 2008, 15:43) *
Значит SPSR не volatile, или используется старый плюсовый IAR. По-моему, дискуссия пошла на второй круг.

SPSR это регистр статуса SPI, все I/O регистры описаны в .h как VOLATILE
компилятор отнюдь не старый, проверил на IAR AVR 5.10 то же самое.
Может быть из-за моей неграмотности, но я так и не понял это все же баг
компилятора, или если данная форма отдана стандартом на реализацию, тогда фитча.
aaarrr
Цитата(VladimirYU @ Nov 11 2008, 14:57) *
компилятор отнюдь не старый, проверил на IAR AVR 5.10 то же самое.

Листинг посмотреть можно?
VladimirYU
Цитата(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          }

То же самое. Чтения нет.
zltigo
Цитата(Непомнящий Евгений @ Nov 11 2008, 14:23) *

Это вообще просто "C" - начиная с K&R. Совершенно переносимо.
aaarrr
Цитата(zltigo @ Nov 11 2008, 15:19) *
Это вообще просто "C" - начиная с K&R. Совершенно переносимо.

Тогда почему в C99 об этом ни слова нет?
VladimirYU
Цитата(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

Евгений абсолютно прав.
zltigo
Цитата(aaarrr @ Nov 11 2008, 15:22) *
Тогда почему в C99 об этом ни слова нет?

Да? Могу, конечно, ошибаться sad.gif. Но все встреченные на жизненном пути компиляторы начиная с TurboC 1.0 такое поддерживали и поддерживают. Удобно очень.
aaarrr
RVCT на пропуск операнда ругается.
ReAl
Цитата(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. с все поймут? Или "все, имеющие уровень образования выше некоторого порога"?
И причём тут маты?
Так что, на мой взгляд, тут скорее "в русском языке много разных способов посттроения предложений, однако для того, чтобы быть понятым всеми, стоит избегать сложных предложений, да и вообще - наличие запятых не ещё не означает, что стоит их ставить в предложениях".
"Все" понимают рекламу, это "хороший стиль рекламы".
Но не все понимают сложный язык литературных произведений, пользующихся всей мощью русского языка и это их хороший стиль. Отменим? Оставим только понимаемые всеми?
aaarrr
Цитата(VladimirYU @ Nov 11 2008, 14:57) *
SPSR это регистр статуса SPI, все I/O регистры описаны в .h как VOLATILE

Они там описаны как __io union, никаких volatile в помине нет.
ReAl
Цитата(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++ и указатели - то же самое, только на более низком пороге "свой-чужой", "общепонятности - не общепонятности". Бывает трудно понимается.
VladimirYU
Цитата(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
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.