Come comprendere e progettare funzioni con argomenti di enumerazione che funzionano in tandem con operatori bit a bit in C ++ e Qt?

1

Nel C ++, ci sono 6 operatori bit a bit:

Symbol  Operator
&       bitwise AND
|       bitwise inclusive OR
^       bitwise XOR (eXclusive OR)
<<      left shift
>>      right shift
~        bitwise NOT (one's complement) (unary)

In Qt, ho visto | , ~ e & usati abbastanza spesso nelle funzioni:

file->open(QIODevice::WriteOnly | QIODevice::Truncate);

L'origine per tale funzione assomiglia a questa:

bool QFile::open(OpenMode mode)
{
    Q_D(QFile);
    if (isOpen()) {
        qWarning("QFile::open: File (%s) already open", qPrintable(fileName()));
        return false;
    }
    if (mode & Append)
        mode |= WriteOnly;

    unsetError();
    if ((mode & (ReadOnly | WriteOnly)) == 0) {
        qWarning("QIODevice::open: File access not specified");
        return false;
    }
    if (fileEngine()->open(mode)) {
        QIODevice::open(mode);
        if (mode & Append)
            seek(size());
        return true;
    }
    QFile::FileError err = fileEngine()->error();
    if(err == QFile::UnspecifiedError)
        err = QFile::OpenError;
    d->setError(err, fileEngine()->errorString());
    return false;
}

Il codice sorgente per l'enumerazione è simile a questo:

enum OpenModeFlag {
    NotOpen = 0x0000,
    ReadOnly = 0x0001,
    WriteOnly = 0x0002,
    ReadWrite = ReadOnly | WriteOnly,
    Append = 0x0004,
    Truncate = 0x0008,
    Text = 0x0010,
    Unbuffered = 0x0020,
    NewOnly = 0x0040,
    ExistingOnly = 0x0080
};
Q_DECLARE_FLAGS(OpenMode, OpenModeFlag)

Nel libro ho imparato Qt e C ++ from, non tocca in modo adeguato questi schemi di progettazione, quindi non sono nemmeno abbastanza sicuro di come leggere questo codice, o in che misura dovrei usare gli Operatori bitwise in tandem con le mie enumerazioni.

Domande

  1. In che modo viene valutata la file->open(QIODevice::WriteOnly | QIODevice::Truncate)); in primo luogo? Valuta entrambe le enumerazioni in questo modo:

    QIODevice::WriteOnly > 0x0002 > 0000 0000 0000 0000 0000 0010
    QIODevice::Truncate  > 0x0008 > 0000 0000 0000 0000 0000 1000
                                  | 0000 0000 0000 0000 0000 1010
    

    ed esegui la funzione in questo modo?

    file->open(0000 0000 0000 0000 0000 1010); // 10 is not set in enum
    
  2. Se questo è il caso, qual è la rilevanza del numero 10 in binario?

  3. Perché i numeri impostati hanno tutti i poteri di 2?
  4. Perché utilizzare gli esadecimali per i numeri e non per gli interi semplici?
  5. Potrebbe essere applicato ogni operatore bit a bit alla funzione e come leggerlo? Questa sarebbe la mia ipotesi rudamentale:

    file->open(QIODevice::WriteOnly & QIODevice::Truncate); // Both have to be true?
    file->open(QIODevice::WriteOnly | QIODevice::Truncate); // At least one has to be true?
    file->open(QIODevice::WriteOnly ^ QIODevice::Truncate); // Only one has to be true?
    file->open(QIODevice::WriteOnly ~ QIODevice::Truncate); // WriteOnly has to be true and Truncate has to be false
    file->open(QIODevice::WriteOnly << QIODevice::Truncate);// ??? 
    file->open(QIODevice::WriteOnly >> QIODevice::Truncate);// ???
    
  6. Nella sorgente della funzione, vedo anche cose come |= ; Che cosa fa?

  7. Come leggere questa riga di codice: if ((mode & (ReadOnly | WriteOnly)) == 0) ?
  8. In termini più pratici, quali sono le circostanze in cui userei ogni operatore bit a bit da utilizzare in tandem con le enumerazioni?

Grazie.

    
posta Akiva 28.11.2018 - 07:30
fonte

1 risposta

5

La tua comprensione è abbastanza buona. Per rispondere alle tue domande:

  1. Sì, la funzione riceverà 0x0000 0000 0000 0000 0000 1010 come argomento.
  2. Il significato del numero decimale 10 in binario è che è composto da 2 bit "on" nelle posizioni 1 e 3. Non c'è motivo di pensare al numero in decimale.
  3. I numeri sono potenze di 2 in modo che ognuno possa rappresentare una bandiera indipendente senza entrare in conflitto con gli altri.
  4. Sono scritti in esadecimale perché è più compatto di quello binario, ma mostra ancora la natura binaria dei numeri. Poiché ognuno è un potere di 2, segue un modello di 0,1,2,4,8 per ogni posizione esadecimale. Quando lo vedi, dovresti immediatamente riconoscerlo come un insieme di flag indipendenti.
  5. Puoi applicare uno di questi operatori, ma probabilmente non farebbero ciò che stai pensando dalla tua descrizione. Usando bit per bit o è l'uso previsto principale, e questo è uno schema che vedrai in molte altre basi di codice. Altri modelli di utilizzo potrebbero entrare in gioco quando si superano i flag ricevuti dalla funzione e non si desidera controllare manualmente tutte le possibili combinazioni di flag. Ad esempio, forse vuoi assicurarti di aprire sempre un file solo in sola lettura, ma vuoi mantenere tutti gli altri flag passati nella funzione. Potresti fare qualcosa come flags = flags & ~WriteOnly . Ciò dice di eseguire un bit per bit e con flags e l'inverso di WriteOnly . L'inverso di WriteOnly ha ogni bit impostato ad eccezione di quello che normalmente si associa a WriteOnly . Quindi questo ha l'effetto di dire: "Voglio che tutto rimanga lo stesso eccetto il WriteOnly flag che voglio sempre essere 0".
  6. Questa non è una domanda, ma se vedi qualcosa come x |= y; significa semplicemente x = x | y . È in bit per bit o come += è in aggiunta.
  7. Lo leggeresti come "Se la variabile mode non ha né ReadOnlyWriteOnly set"
  8. Gli operatori bit a bit vengono utilizzati con le enumerazioni quando i valori delle enumerazioni sono potenze di 2 che rappresentano flag indipendenti (booleani, in sostanza). A volte invece di rendere le enumerazioni 2 n , le enumerazioni sono solo n . In questi casi, costruisci il flag che vuoi facendo x = 1 << flag dove flag è n . Quindi per bit 0, flag = 0, per bit 1, flag = 1.
risposta data 28.11.2018 - 08:06
fonte

Leggi altre domande sui tag