2012-01-02 16 views
5

OK może brzmieć trochę niejasno z tytułu, ale to dlatego, że nie mam pojęcia, jak inaczej to wyrazić. Spróbuję wyjaśnić, co mam na myśli: bardzo często w niektórych bibliotekach funkcja "init" akceptuje niektóre parametry, ale ten parametr akceptuje wiele parametrów (prawy ..). Przykładem byłoby tak:Wiele parametrów w jednym parametrze (funkcje) w C/C++

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); 

Jak to działa? Nie mogę znaleźć nigdzie odpowiedzi, najprawdopodobniej dlatego, że nie wiem, jak to się nazywa, więc nie mam pojęcia, czego szukać. Byłoby to bardzo przydatne w moim obecnym projekcie.

Z góry dziękuję!

+2

Jak to napisał, to ** wygrał t ** działa, ponieważ flagi nie ustawiają różnych bitów. –

+0

To zdaję sobie sprawę, było to głównie dla celów przykładowych. Wybacz mi, nie spałem od 30 godzin! :( –

Odpowiedz

5

Ten piąty parametr jest zwykle maską. Działa poprzez zdefiniowanie kilku stałych (prawdopodobnie enum) z wartościami, które są potęgami dwóch lub ich kombinacjami. Następnie są one kodowane do pojedynczej wartości przy użyciu | i dekodowane przy użyciu &. Przykład:

#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 
    // .. 
} 
+0

Dokładnie to musiałem wiedzieć. Dziękuję bardzo, mam trochę _figured_ było coś takiego, ale nie mogłem znaleźć przykład w dowolnym kodzie źródłowym przeglądałem! –

+0

Nie ma za co. – Gorpik

9

Parametr jest zwykle nazywany "flagami FOO $", a wartościami są or -ed. Chodzi o to, że parametr jest typem liczbowym, który jest skonstruowany jako bitowe or o wielu możliwych wartościach.

W funkcji przetwarzania, wartości są zwykle testowane z bitowego and:

if ((flags & API_FULLSCREEN) != 0) 

Trzeba być ostrożnym, aby przypisać wartości w sposób, który utrzymuje lub liniowy operacji. Innymi słowy, nie ustawiaj tego samego bitu w dwóch różnych wartościach, jakie można ustawić w nagłówku. Na przykład,

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

działa i pozwala na dekonstrukcji wszystkie kombinacje flag w swojej funkcji, ale

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

nie dlatego API_FULLSCREEN | API_NO_DELAY == API_BLAH_BLAH.

Wyświetlanie z wyższego poziomu flagi int jest listą zmiennych argumentów biednego mężczyzny. Jeśli weźmiesz pod uwagę C++, powinieneś zamknąć te szczegóły w klasie lub przynajmniej std::bitset.

+0

I korzystnie działa w C, więc myślę, że w ten sposób będę musiał spojrzeć w do teraz. Jednak będę musiał zerknąć na std :: bitset, jak dobrze jest wiedzieć takie rzeczy bym zakładamy. Twoja odpowiedź była najbardziej pouczające, dziękuję! –

+0

postanowiłem oznaczyć inne pytanie, odpowiedź, jak to pod warunkiem, bardziej namacalny przykład. Naprawdę chcę zaznaczyć obie odpowiedzi chociaż, więc ja po prostu chciałem podziękować jeszcze raz. :) –

+0

Twój bitowy przykład 'i' jest niepoprawny. Operator pierwszeństwa oznacza, że ​​trzeba nawiasy, aby uzyskać zamierzony efekt: 'if ((flagi i API_FULLSCREEN) = 0!)'. – ChrisN

1

To, co tam robią, polega na użyciu binarnych OR do łączenia flag.

więc co się rzeczywiście dzieje jest:

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

Jest jeszcze jeden parametr, ale 3 flagi będą tworzą unikalną wartość dla tego parametru, który może być wykorzystywany w funkcji.

+0

Pomyślałem, że to coś takiego, ale kilka rzeczy przychodzi mi na myśl. Na przykład, co jeśli wynik dwóch flag byłby taki sam? Czy mógłbyś dać szybki i brudny praktyczny przykład tego, jak to działa? Czy musiałbym najpierw obliczyć -wszystko-możliwości, a następnie zrobić przełącznik (flagi) {/ * sprawy tu idą * /} –

+0

@JesseBrands Programista musiałby się upewnić, że same nie ma identycznych wartości. Więc tak, musiałbyś dokonać przełączenia z prekomputowanymi wartościami flag. – Serdalis

+1

@JesseBrands: Flagi muszą być prostopadłe oczywiście. Dla wektora bitowego oznacza to, że każda flaga ustawia dokładnie jeden określony bit (i być może jakiś nieortogonalny bit maski, aby wskazać, że jedna z grup flag została w ogóle użyta). – datenwolf

1

To, co definiujesz jako wiele parametrów, jest ściśle pojedynczym parametrem z punktu widzenia podpisu funkcji. Jeśli chodzi o obsługę wielu Options na podstawie pojedynczego parametru, jak widać, jest bitwise Or Operator, który ustawia pojedynczą wartość dla wartości parametru. Ciało funkcji wykorzystuje następnie pojedyncze bity do określenia pełnych ustawień.

Zazwyczaj jeden bit jest alokowany dla jednej opcji i zwykle mają dwie wartości stanu (prawda/fałsz).

0

bitowe OR

bitowe OR działa niemal dokładnie taki sam sposób, jak bitowego AND. Jedyna różnica polega na tym, że tylko jeden z dwóch bitów musi być równy 1, aby bit tej pozycji w wyniku wynosił 1. (Jeśli oba bity są równe 1, wynik będzie miał także 1 w tej pozycji.) Symbolem jest fajka: |. Ponownie jest to podobne do logicznego operatora boolowskiego, którym jest ||.

01001000 | 10111000 = 11111000

i w konsekwencji 72 | 184 = 248

Tak więc w metodzie nie wielokrotny parametr jest rzeczywiście jeden parametr. możesz użyć operacji Bitwise OR opearation na API_FULLSCREEN | API_NO_DELAY | API_BLAH_BLAH i przekazał go w metodzie.

0

Podany przykład nie działa zgodnie z oczekiwaniami. Co możesz zrobić, to użyć konkretnego bitu dla danej opcji - a następnie łączy LUB

Przykład

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

Więc bit 1 jest dla OPT1, bit 2 jest dla OPT2 itp

Więc OPT1 | OPT3 ustawia bit 1 i 3 oraz daje wartości 5

w funkcji można sprawdzić, czy dana opcja jest wymagana przy użyciu opera i Tor

Więc

void perform(int opts) 
{ 
if (opts & OPT1) 
{ 
// Do stuff for OPT1 
} 
... 
1

Parametr jest zwykle nazywane „flagi” i zawiera kombinację lub ED zbioru dozwolonych wartości.

int flags = API_FULLSCREEN | API_NO_DELAY; 

Funkcja Czy brać ten parametr liczbę całkowitą i wyodrębnić poszczególne elementy tak:

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

dla tej pracy trzeba być carfull w jaki sposób ktoś wybiera wartości liczbowych dla API_ * parametry.

0

Wartość tych parametrów jest określona w taki sposób, że nie nakładają się na siebie.Coś takiego:

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

Biorąc pod uwagę powyższe definicje, twój może zawsze określić, które z powyższych zmiennych zostały OR ed za pomocą operatora bitowe 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; 
}