#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 » Что здесь происходит? «,
~
не возвращает значение lvalue2. @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.