È buona prassi lanciare mai un booleano su un intero per l'aritmetica?

5

Se ho una funzione in cui sto operando su uno specifico offset all'interno di una stringa, e la posizione esatta di questo offset dipende da un test precedente all'interno della funzione, è "cattiva pratica" o "brutta" usare il booleano nell'aritmetica in cui viene calcolato l'offset?

Ecco la mia funzione:

#include <Windows.h>
#include <strsafe.h>

VOID WINAPI TrimQuotes(WCHAR *wStr, INT cchStr, WCHAR *wOut, INT cchOut)
{
    WCHAR wStart = wStr[0];
    WCHAR wEnd = wStr[cchStr-1];

    if(wStart == L'\"')
        StringCchCopy(wOut, cchOut, wStr+1);
    else
        StringCchCopy(wOut, cchOut, wStr);
    if(wEnd == L'\"')
        wOut[cchStr-(1+(wStart==L'\"'))]=L'
#include <Windows.h>
#include <strsafe.h>

VOID WINAPI TrimQuotes(WCHAR *wStr, INT cchStr, WCHAR *wOut, INT cchOut)
{
    WCHAR wStart = wStr[0];
    WCHAR wEnd = wStr[cchStr-1];

    if(wStart == L'\"')
        StringCchCopy(wOut, cchOut, wStr+1);
    else
        StringCchCopy(wOut, cchOut, wStr);
    if(wEnd == L'\"')
        wOut[cchStr-(1+(wStart==L'\"'))]=L'%pre%';
}
'; }

Come probabilmente hai indovinato dal suo nome, il suo compito è determinare se una stringa è circondata da caratteri a virgolette e, in tal caso, rimuoverli dalla stringa. Se ho rimosso un carattere dalla stringa di origine già nel caso in cui wStart == L'\"' , quindi l'offset all'interno della stringa di destinazione in cui l'ultimo carattere non nullo è decrementato di uno, quindi la mia soluzione era semplicemente il cast booleano in un numero intero che regolerebbe l'offset da cchStr se necessario:

Consiglieresti di fare questo?

    
posta Govind Parmar 22.11.2016 - 21:24
fonte

3 risposte

6

Esiste una differenza pratica tra l'utilizzo di una tecnica di codifica ben nota e ben compresa e un'esotica e ad-hoc che dovrà essere analizzata da altri programmatori per capire cosa fa.

Ad esempio

while (i) { 

Chiunque sia un programmatore C con una piccola esperienza capisce come funziona. Quando i raggiunge zero, il ciclo termina.

La tua tecnica? Non così tanto.

Se fossi in te, favorirei la chiarezza del codice rispetto all'abilità.

    
risposta data 22.11.2016 - 21:45
fonte
5

Nel tuo originale, usi una variabile locale per estrarre il primo carattere, quindi usa quel locale due volte ma nella stessa esatta espressione. Dal momento che l'hai già provato una volta, non abbiamo bisogno dei due confronti booleani, uno dei quali è l'oggetto della domanda ed è potenzialmente potenzialmente confuso.

Poiché può essere facilmente eliminato, perché non farlo?

Inoltre, non stai gestendo stringhe vuote.

Penso che quanto segue sia più leggibile: la logica principale utilizza ...CopyN e non è condizionale. Solo le regolazioni per la posizione iniziale e finale richiedono una logica condizionale. Ogni condizione di confronto dei caratteri viene testata solo una volta.

VOID WINAPI TrimQuotes ( WCHAR *wStr, INT cchStr, WCHAR *wOut, INT cchOut )
{
    if ( cchStr > 0 && wStr[cchStr-1] == L'\"' )
        cchStr--;

    if ( cchStr > 0 && wStr[0] == L'\"' ) {
        wStr++;
        cchStr--;
    }

    StringCchCopyN ( wOut, cchOut, wStr, cchStr );
}
    
risposta data 22.11.2016 - 21:45
fonte
2

La conversione di un valore booleano in numeri interi può talvolta essere una soluzione elegante, ad es. quando cerchi di evitare le diramazioni come ottimizzazione a livello ultrabasso o quando cerchi di prevenire attacchi di temporizzazione.

Per qualsiasi altra cosa, è meglio cercare il codice più leggibile e più gestibile. Il codice intelligente è un codice pericoloso, perché potremmo perdere un bug. E 'ovvio cosa faccia questa ultima affermazione? Non proprio.

Nota anche che il tuo strano flusso di controllo rimuoverà la prima citazione iniziale e l'ultima citazione finale anche quando la stringa non è racchiusa tra virgolette:

"foo   → foo
""foo  → "foo
foo"   → foo
foo""  → foo"
"foo"  → foo
""foo" → "foo
...

È davvero questo il comportamento previsto? Se si desidera rimuovere solo le virgolette allegate, mi aspetto un codice come questo: (pseudocodice)

TrimQuotes(in, out):
  if in[0] == '"' and in[-1] == '"':
    copy in[1, ..., -2] into out
  else:
    copy in into out

Se volessi rimuovere un preventivo iniziale e finale anche se non corrispondono, mi aspetterei qualcosa di simile:

TrimQuotes(in, out):
  first = 0
  last = length of in - 1
  if in[first] == '"':
    first++
  if in[last] == '"':
    last--
  copy in[first, ..., last] into out

Se vuoi rimuovere un numero qualsiasi di frasi iniziali e finali, mi aspetto:

TrimQuotes(in,  out):
  first = 0
  last = length of in - 1
  while in[first] == '"':
    first++
  while in[last] == '"':
    last--
  copy in[first, ..., last] into out

Qualcuno di questi mostra più chiaramente perché stai spostando gli indici in quale direzione. Il calcolo di tutti gli indici prima di eseguire la copia impedisce inoltre di copiare più del necessario. Nel tuo codice, copi ancora l'ultimo carattere anche se verrà cancellato.

Un altro aspetto curioso è che la tua funzione esegue una copia. Il taglio della stringa può essere fatto interamente incrementando il puntatore e diminuendo il numero di caratteri (come dimostrato nella risposta di Erik Eidt). Se il chiamante richiede una copia modificabile, potrebbe crearne uno da solo.

    
risposta data 22.11.2016 - 21:48
fonte

Leggi altre domande sui tag