Come scrivere una funzione constexpr
per scambiare l'endianess di un intero, senza fare affidamento sulle estensioni del compilatore e puoi dare un esempio su come farlo?Come scrivere la funzione di scambio constexpr per cambiare l'endianess di un intero?
risposta
Sì, è piuttosto semplice; ecco un'implementazione ricorsiva (C++ 11-compatibile) (solo tipi interi senza segno):
#include <climits>
#include <cstdint>
#include <type_traits>
template<class T>
constexpr typename std::enable_if<std::is_unsigned<T>::value, T>::type
bswap(T i, T j = 0u, std::size_t n = 0u) {
return n == sizeof(T) ? j :
bswap<T>(i >> CHAR_BIT, (j << CHAR_BIT) | (i & (T)(unsigned char)(-1)), n + 1);
}
Qui sto usando j
come l'accumulatore e n
come il contatore di ciclo (indicizzazione bytes) .
Se si dispone di un compilatore di supporto C++17 fold expressions, è possibile scrivere qualcosa che si espande fuori in esattamente quello che ci si scrive a mano:
template<class T, std::size_t... N>
constexpr T bswap_impl(T i, std::index_sequence<N...>) {
return ((((i >> (N * CHAR_BIT)) & (T)(unsigned char)(-1)) <<
((sizeof(T) - 1 - N) * CHAR_BIT)) | ...);
}; // ^~~~~ fold expression
template<class T, class U = typename std::make_unsigned<T>::type>
constexpr U bswap(T i) {
return bswap_impl<U>(i, std::make_index_sequence<sizeof(T)>{});
}
Il vantaggio di questa forma è che perché non usa loop o ricorsione, sei praticamente garantito per ottenere un output di assemblaggio ottimale - su x86-64, clang arriva anche a work out to use the bswap
instruction.
Ispirato da ecatmur suggerisco la seguente soluzione, che ha prestazioni potenzialmente migliori quando bswap non viene rilevato dal compilatore (O (log (n)) vs O (N)). Dato che N è di solito < = 8 questo è probabilmente irrilevante, ancora:
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value,T>::type
constexpr alternating_bitmask(const size_t step){
T mask(0);
for (size_t i=0;i<digits<T>();i+=2*step){
mask|=(~T(0)>>(digits<T>()-step))<<i;
}
return mask;
}
template <typename T>
typename std::enable_if<std::is_unsigned<T>::value,T>::type
constexpr bswap(T n){
for (size_t i=digits<unsigned char>();i<digits<T>();i*=2){
n = ((n&(~(alternating_bitmask<T>(i))))>>i)|
((n&((alternating_bitmask<T>(i))))<<i);
}
return n;
}
Poiché questa forma è più complessa di quanto la soluzione di ecatmur il compilatore ha un difficile ottimizzazione del lavoro, ma clang trova ancora che intendiamo bswap.
Questa soluzione ha in realtà una complessità temporale di Θ (N), poiché il ciclo interno (senza contare le ottimizzazioni) ha una complessità ammortizzata di Θ (N/log N) (per iterazione del ciclo esterno). Per ottenere l'effettivo Θ (log N), le maschere di bit dovrebbero essere memoizzate, ad es. precompilato in un array. –
@ArneVogel questo è vero, ho appena assunto che le maschere di bit saranno costanti di tempo di compilazione in quanto la funzione che le genera è un constexpr. – Lykos
- 1. F #: come scrivere la funzione di scambio classico?
- 2. Simboli non definiti per la funzione constexpr
- 3. come cambiare la variabile di intervallo in un tipo intero?
- 4. sort() - Nessuna funzione di corrispondenza per la chiamata a "scambio"
- 5. La funzione di ritorno di constexpr non viene compilata
- 6. Inizializzazione di un array con un constexpr?
- 7. Utilizzando un lambda in un `funzione di constexpr` in un contesto non-`constexpr`: clang vs gcc
- 8. constexpr void funzione respinta
- 9. È possibile implementare addressof() come funzione constexpr?
- 10. Scambio bit aritmetico su un numero intero con segno
- 11. C++ 11 constexpr parametro di funzione passaggio
- 12. Bash: scrivere per intero file binario
- 13. Cambiare funzione interna di un pacchetto
- 14. statico constexpr variabile vs funzione
- 15. Perché questa funzione membro statico di constexpr non è vista come constexpr quando viene chiamata?
- 16. Funzione attualmente chiamata per scrivere la funzione ricorsiva anonima
- 17. Come scrivere un riferimento di funzione in un modulo Perl?
- 18. delegato/funzione di scambio e interfaccia in D2
- 19. Come scrivere una funzione generica su un tipo di puntatore?
- 20. Semplice funzione di scambio ... perché questo non scambia?
- 21. Come cambiare la lingua di un WebDriver?
- 22. Come cambiare la dimensione di un popover
- 23. Utilizzo di "constexpr" per utilizzare la stringa letterale per il parametro modello
- 24. Come contrassegnare un parametro della funzione constexpr inutilizzato?
- 25. Come cambiare eregi di PHP per funzione preg_match
- 26. Come cambiare le lettere di una parola da maiuscolo a minuscolo o viceversa (caso di scambio)?
- 27. Puntatori di scambio C++
- 28. Come scrivere una funzione di PowerShell per ottenere le directory?
- 29. Perché GCC pensa che la definizione di membro di dati statici di constexpr debba essere contrassegnata come constexpr?
- 30. Come scrivere un test di prova dell'unità per una funzione che restituisce un frame di dati
Qual è la "endianità di un intero"? Qual è il endianness di 15? –
@KerrekSB Qualunque cosa sia. Non ho fatto quella domanda. La mia domanda è come scambiare big-endian con little-endian e viceversa. – user1095108
@KerrekSB: Nel contesto del C++ (e della maggior parte della programmazione in generale), quando si dice intero, di solito si riferiscono a un oggetto intero. Cioè, una regione in memoria utilizzata per memorizzare i dati interi, di solito uno dei tipi interi fondamentali (char, short, int, long e long long, insieme alle loro varianti senza segno). Non hai mai incontrato questo utilizzo? –