Предупреждения компилятора макроса C - PullRequest
0 голосов
/ 15 марта 2019

Я определил макрос, используя входные данные из предыдущего вопроса, который я задал здесь . Макрос предназначен для установки, очистки или проверки состояния контактов GPIO. Макрос работает, как и ожидалось, однако проблема возникает при компиляции. Я получаю предупреждения компилятора везде, где он используется:

Предупреждение правого операнда выражения с запятой не имеет значения

когда я использую макрос следующим образом:

#define ON  1
#define OFF 2
#define ENA 3
#define OUT_3(x) (x==ON) ? (PORTJ.OUTSET=PIN2_bm) : (x==OFF) ? (PORTJ.OUTCLR=PIN2_bm) : (x==ENA) ? (PORTJ.DIRSET=PIN2_bm) : (PORTJ.DIRCLR=PIN2_bm)
#include <avr/io.h>

if (something) OUT_3(ENA);

Однако, если я сделаю это:

if (something) {OUT_3(ENA);}

Я больше не получаю предупреждения.

Почему есть разница? Как я должен изменить макрос, чтобы предотвратить этот сценарий?

Дополнительно это вызывает предупреждение:

int i=0;
if (something) i=1, OUT_3(ENA);

Однако это не так:

int i=0;
if (something) OUT_3(ENA), i=1;

Мое понимание выражений через запятую явно не так. Как компилятор видит это? Я посмотрел на несколько других вопросов, похожих на этот, но все еще не до конца понял разницу.

Ответы [ 2 ]

5 голосов
/ 15 марта 2019

Этот макрос неприятен по нескольким причинам:

  1. Параметры макроса всегда должны быть заключены в круглые скобки, чтобы избежать потенциальных проблем с приоритетом оператора. Измените (x==ON) на ((x)==ON).
  2. Вложенные троичные операции должны быть заключены в круглые скобки, чтобы сделать порядок выполнения очевидным. Измените a ? b : c ? d : e на a ? b : (c ? d : e).
  3. Полный макрос должен быть заключен в круглые скобки #define MACRO (...) или цикл do-while-zero #define MACRO do {...} while(0), чтобы избежать возможных проблем с приоритетом оператора. Подробнее ниже.
  4. Тернарный оператор здесь не очень полезен, поскольку вы не используете его возвращаемое значение. Вы должны использовать обычные операторы if или switch. Вот где ранее упомянутый цикл do-while-zero становится полезным:

    #define OUT_3(x) \
        do { \
            if((x) == ON)       { PORTJ.OUTSET = PIN2_bm; } \
            else if((x) == OFF) { PORTJ.OUTCLR = PIN2_bm; } \
            else if((x) == ENA) { PORTJ.DIRSET = PIN2_bm; } \
            else                { PORTJ.DIRCLR = PIN2_bm; } \
        } while(0)
    
  5. Но действительно ли нужен макрос? Вместо этого вы можете использовать встроенную функцию и избавиться от всех макросов:

    static inline void OUT_3(x_type x) {
        if(x == ON)       { PORTJ.OUTSET = PIN2_bm; }
        else if(x == OFF) { PORTJ.OUTCLR = PIN2_bm; }
        else if(x == ENA) { PORTJ.DIRSET = PIN2_bm; }
        else              { PORTJ.DIRCLR = PIN2_bm; }
    }
    

С этими изменениями ваша ошибка, вероятно, исчезнет, ​​и ваш код будет намного легче читать.

1 голос
/ 15 марта 2019

Я не могу воспроизвести вашу проблему. Этот код работает без проблем

main.cpp

#include <stdio.h>
enum type{ON, OFF, ENA};

#define OUT_3(x) (x==ON) ? (printf("ON\n")) : (x==OFF) ? (printf("OFF\n")) : (x==ENA) ? (printf("ENA\n")) : (printf("OTHER\n"))

int main(){
  int a = 2;
  if(a == 1) OUT_3(ON);
  if(a == 2) OUT_3(OFF);
  if(a == 3) OUT_3(ENA);

  return 0;
}

Скомпилировано с

gcc -Wall -O0 -g -o main main.c

Не могли бы вы показать, как выглядят определения ON, OFF, ENA и определения портов?

...