Как вы принимаете адрес инвертированного составного файла в C?

#arrays #c #function #integer #integer-promotion

#массивы #c #функция #целое число #целочисленное продвижение

Вопрос:

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

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

 #define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(amp;BIT0);
}
  

Все работает отлично для обычного значения, но в моем случае мне нужно иметь возможность инвертировать значение, поэтому я решил, что это сработает:

 #define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(amp;~BIT0);
}
  

Просто инвертируйте значение с помощью побитового NOT (~) при его передаче. Ничего особенного, верно? Ну, я получаю ошибку

 error: lvalue required as unary 'amp;' operand
  

Если я перепишу его как:

 #define BIT0 (unsigned char){0b00000001}

void    foo (unsigned char *ptr_bar)
{
    printf("%x", *ptr_bar);
}

void    main    (void)
{
    foo(amp;(unsigned char){~BIT0});
}
  

Во-первых, это очень уродливое решение, и я действительно не хочу использовать его в своем коде. Это совсем не интуитивно понятно.
Во-вторых, это работает так, как я хотел, чтобы это работало изначально, но я полагаю, что это говорит мне о том, что оператор ‘~’ переводит unsigned char в unsigned int. Поэтому я должен преобразовать его обратно в символ без знака, чтобы функция могла принять адрес. Но сообщение об ошибке на самом деле не совпадает с тем, что меня смущает.

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

Комментарии:

1. Re » Что здесь происходит? «, ~ не возвращает значение lvalue

2. @ikegami Ааааа ладно. Я не знал об этом. Это объясняет ошибку. Есть ли какой-либо способ обойти это без необходимости создания второго составного литерала?

3. ~ необходимо применить к значению внутри фигурных скобок, например #define NOTBIT0 (unsigned char){~0b00000001}

4. Значение lvalue — это (приуменьшая некоторые детали) выражение, которое ссылается на объект. Унарный amp; оператор требует lvalue в качестве своего аргумента — это означает, что должен быть какой-то объект, адрес которого вы вычисляете. ~ Команда применяется к значению, а не к объекту, и выдает его.

5. Названия происходят от того факта, что это те вещи, которые вы находите на L правой стороне оператора присваивания. Это означает, что вы не можете получить адрес чего-то, у чего, скорее всего, его нет.

Ответ №1:

Причина ошибки в том, что некоторые операторы (например, унарные * ) возвращают так называемое изменяемое значение, означающее ссылку на объект, который вы можете изменить. Однако большинство операторов этого не делают, и ~ является таким оператором. Все, что вы получаете от него, — это временное значение, доступное только для чтения. Это действительно также переводит операнд в signed int , что часто проблематично, но не является причиной ошибки.

Что касается того, как решить проблему, это в том, как вы используете эти макросы. Если BIT0 является составным литералом с установленным битом 0, то для обеспечения последовательности, вероятно, можно было бы создать аналогичный макрос:

 #define BITS1_7 (unsigned char){0xFE}
  

(Обратите внимание, что двоичные литералы не являются стандартными C.)

Но я бы тоже этого не сделал. Корень проблемы заключается в чрезмерной разработке и настаивании на использовании составных литералов странными способами. Вместо этого примените принцип KISS. Если у вас есть функция, принимающая либо один байт, либо массив, то наиболее удобным способом написания программы будет:

 #define BIT0 (1u << 0) // industry de facto standard way to write a bit mask
...

uint8_t tmp = BIT0;
foo(amp;tmp);
  

в качестве альтернативы

 uint8_t tmp = ~BIT0;
  

Этот код может быть прочитан и понят всеми программистами на C.