Несколько параметров в одном параметре (функции) в C / C ++ - PullRequest
5 голосов
/ 02 января 2012

Хорошо, это может звучать немного расплывчато из названия, но это потому, что я понятия не имею, как сказать это по-другому.Я попытаюсь объяснить, что я имею в виду: очень часто в определенных библиотеках функция 'init' принимает некоторые параметры, но затем этот параметр принимает несколько параметров (справа ..).Пример будет выглядеть так:

apiHeader.h

#define API_FULLSCREEN   0x10003003
#define API_NO_DELAY     0x10003004
#define API_BLAH_BLAH    0x10003005

main.c:

apiInit(0, 10, 10, 2, API_FULLSCREEN | API_NO_DELAY | API_BLAH_BLAH);

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

Заранее спасибо!

Ответы [ 8 ]

9 голосов
/ 02 января 2012

Параметр обычно называется «$ FOO flags», а значения * -1001 * -ed.Дело в том, что параметр является числовым типом, который создается как побитовый or из нескольких возможных значений.

В функциях обработки значения обычно проверяются с помощью побитового and:

if ( (flags & API_FULLSCREEN) != 0 )

Необходимо соблюдать осторожность при назначении значений таким образом, чтобы операция ИЛИ была линейной.Другими словами, не устанавливайте один и тот же бит в двух разных значениях or, как вы делали в заголовке.Например,

#define API_FULLSCREEN   0x1
#define API_NO_DELAY     0x2
#define API_BLAH_BLAH    0x4

работает и позволяет вам деконструировать все комбинации флагов в вашей функции, но

#define API_FULLSCREEN   0x1
#define API_NO_DELAY     0x2
#define API_BLAH_BLAH    0x3

нет, потому что API_FULLSCREEN | API_NO_DELAY == API_BLAH_BLAH.

ПросмотрНа более высоком уровне флаг int представляет собой список переменных аргументов бедняков.Если вы рассматриваете C ++, вы должны инкапсулировать такие детали в классе или хотя бы в std::bitset.

6 голосов
/ 02 января 2012

Этот пятый параметр обычно является маской.Он работает путем определения нескольких констант (вероятно, enum) со значениями, которые являются степенями двух, или их комбинациями.Затем они кодируются в одно значение с использованием | и декодируются с использованием &.Пример:

#define COLOUR_RED   0x01
#define COLOUR_GREEN 0x02
#define COLOUR_BLUE  0x04
#define COLOUR_CYAN  (COLOUR_BLUE | COLOUR_GREEN) // 0x06

// Encoding
SetColour(COLOUR_RED | COLOUR_BLUE); // Parameter is 0x05

// Decoding
void SetColour(int colour)
{
  if (colour & COLOUR_RED) // If the mask contains COLOUR_RED
    // Do whatever
  if (colour & COLOUR_BLUE) // If the mask contains COLOUR_BLUE
    // Do whatever
  // ..
}
1 голос
/ 02 января 2012

Параметр обычно называется "flags" и содержит комбинацию or-ed набора допустимых значений.

int flags = API_FULLSCREEN | API_NO_DELAY;

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

int fullscreen_set = flags & API_FULLSCREEN;
int no_delay_set   = flags & API_NO_DELAY;
int blah_blah_set  = flags & API_BLAH_BLAH;

Чтобы это работало, нужно быть осторожным в выборе числовых значений для параметров API_ *.

1 голос
/ 02 января 2012

То, что вы определяете как множественный параметр, является строго одним параметром с точки зрения сигнатуры функции. Что касается обработки нескольких Options на основе одного параметра, как вы можете видеть, есть bitwise Or Operator, который устанавливает одно значение для значения параметра. Затем тело функции использует отдельные биты для определения полных настроек.

Обычно один бит выделяется для одной опции, и они обычно имеют два значения состояния (истина / ложь).

1 голос
/ 02 января 2012

То, что они там делают, использует двоичный OR для объединения флагов.

, так что на самом деле происходит:

0x10003003 | 0x10003004 | 0x10003005 == 0x10003007

Это все ещеодин параметр, но 3 флага объединятся, чтобы создать уникальное значение для этого параметра, которое можно использовать в функции.

0 голосов
/ 02 января 2012

Значения этих параметров определены таким образом, чтобы они не перекрывались. Примерно так:

#define A 0x01
#define B 0x02
#define C 0x04
#define D 0x08

Учитывая приведенные выше определения, вы всегда можете определить, какие из приведенных выше переменных были OR отредактированы, используя побитовый оператор AND:

void foo(int param)
{
    if(param & A)
    {
         // then you know that A has been included in the param
    }
    if(param & B)
    {
         // then you know that B has been included in the param
    }
    ...     
}

int main()
{
    foo (A | C);
    return 0;
}
0 голосов
/ 02 января 2012

Пример, который вы привели, не будет работать, как ожидалось.Что вы делаете, это используете конкретный бит для конкретной опции - и ИЛИ объединяет тогда

Пример

#define OPT1 1
#define OPT2 2
#define OPT3 4

Таким образом, бит 1 для OPT1, бит 2предназначен для OPT2 и т. д.

Так OPT1 | OPT3 устанавливает биты 1 и 3 и дает значение 5

В функции вы можете проверить, требуется ли конкретная опция, используя AND оператор

Итак

void perform(int opts)
{
if (opts & OPT1)
{
 // Do stuff for OPT1
}
...
0 голосов
/ 02 января 2012

Побитовое ИЛИ

Побитовое ИЛИ работает почти точно так же, как и побитовое И.Единственное отличие состоит в том, что только один из двух битов должен быть 1 для бита этой позиции в результате равным 1. (Если оба бита равны 1, результат также будет иметь 1 в этой позиции.) Символтруба: |Опять же, это похоже на логический логический оператор, который является ||.

01001000 |10111000 = 11111000

и, следовательно, 72 |184 = 248

Так что в вашем методе не множественный параметр, это фактически один параметр.Вы можете использовать побитовую операцию ИЛИ на API_FULLSCREEN |API_NO_DELAY |API_BLAH_BLAH и передал его в метод.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...