2015-09-28 15 views
8

Ho mal di testa che induce problemi qui.Quando int non è un int (intX_t)

Fondamentalmente sto cercando di rendere una libreria compatibile con diversi sistemi Arduino (non una domanda Arduino).

Ho una situazione in cui i tipi non corrispondono più, poiché in un int non è più equivalente al suo identico tipo di larghezza fissa. Nell'ambiente limitato fornito (senza stdlib e così via) ho scritto le mie classi di caratteri del tipo per le funzionalità di cui ho bisogno.

Tutto funziona correttamente tramite GCC 4.8.1 (avr) & Extensa-1x106-GCC (ESP8266), ma non in GCC 4.8.3 (SAM, core SAMD).

Fondamentalmente ho nocche verso il basso il mio codice per mostrare il problema in questo codice molto semplice (int è confermato di avere 4 byte sui mancanza compilatori piattaforma a 32 bit):

template < typename T, typename U > struct is_same{ enum { value = false }; }; 
template < typename T > struct is_same< T, T > { enum { value = true }; }; 

void setup() { 
    static_assert(is_same<int,int32_t>::value, "Not integer"); 
} 

void loop(){} 

è possibile visualizzare un ' normale 'implementazione C++ qui (sopra è un'implementazione di base per l'uso all'interno dell'IDE di Arduino): http://cpp.sh/377e

A proposito, l'asser statico non si attiva neanche nel compilatore cpp.sh.

È 4.8.1 errato, ovvero int e int32_t devono essere considerati tipi diversi. O è 4.8.3 errato e dovrebbero essere equivalenti se uguali dimensioni definite dall'implementazione.

Stavo usando il codice qui sotto per rilevare qualsiasi tipo di numero intero, che era dove ho trovato il mio errore in origine.

template< typename T > 
    struct is_integer{ 
     enum{ 
      V8 = is_same< T, uint8_t >::value || is_same< T, int8_t >::value, 
      V16 = is_same< T, uint16_t >::value || is_same< T, int16_t >::value, 
      V32 = is_same< T, uint32_t >::value || is_same< T, int32_t >::value, 
      V64 = is_same< T, uint64_t >::value || is_same< T, int64_t >::value, 
      value = V8 || V16 || V32 || V64 
     }; 
}; 

io ovviamente può cambiare a verificare la presenza di char, int, long, ecc .. ma sarà ancora bisogno di controllo per tutte le varianti a larghezza fissa e molto probabilmente le int_fastX_t e int_leastX_t tipi, che sembra un super metodo ridondante per garantire la massima usabilità.

Qualche idea?

Saluti, apprezzo qualsiasi input!

+1

La toolchain in questione è disponibile da qualche parte? – melak47

+0

puoi usare [boost] (http://www.boost.org/doc/libs/1_59_0/libs/integer/doc/html/boost_integer/traits.html) nel tuo ambiente embedded? –

+0

@ melak47 Sì, è possibile scaricare [Arduino IDE] (https://www.arduino.cc/en/Main/Software) e dal menu Strumenti-> Scheda-> Gestione schede selezionare e installare il SAM, oppure Core SAMD per una delle catene in errore (farà il resto), quindi selezionare Zero (SAMD) o Due (SAM) dall'elenco Strumenti-> Scheda. (È un dolore, ma progettato per i principianti). Il core AVR 4.8.1 è fornito di default. –

risposta

4

Questo è regolato dallo standard C; il C++ eredita il comportamento con riferimento esplicito.

quello che dice lo standard C è:

  • Se int32_t è definito, si riferisce ad un intero con segno complemento a 32 bit 2 di.

  • Se l'implementazione fornisce un tipo intero a complemento firmato di 32-bit 2, deve fornire il typedef int32_t che si riferirà ad esso.

Da nessuna parte si dice che questo a 32 bit 2 complemento firmato tipo intero deve essere int.Dal punto di vista tecnico, anche se è un tipo intero di complemento a 32-bit 2, è perfettamente possibile che l'implementazione fornisca anche un distinto tipo di intero firmato a 32 bit 2 e definisca int32_t per riferirsi a quell'altro tipo.

Temo che l'unica soluzione completamente generica sia quella di elencare tutti i tipi fondamentali, i tipi a larghezza fissa, i tipi con larghezza minima e quelli con larghezza minima veloce.

Per qualcosa di meno scoraggiante, dovrebbe essere possibile esaminare la documentazione delle toolchain che si desidera supportare per trovare quali tipi forniscono e come vengono denominati. Se questo insieme di "toolchain che desideri supportare" è illimitato, non penso che esista una via d'uscita più semplice.

+1

Puoi renderlo un po 'meno folle creando un modello di tratti che produca larghezza min veloce, larghezza fissa, larghezza minima e larghezza minima per una data dimensione e senso di firma. Questo almeno rompe gli elenchi in pezzi gestibili. Lanciati in elenchi di tipi di tutti i tipi fondamentali (e firmness), più size_t e altri tipi integrali simili di provvidenza indefinita, e poi alcuni metaprogrammazione per operare su tutti questi in modo uniforme ... – Yakk

+0

Elenco di tutti i tipi sicuramente coprirebbe tutto, tuttavia, in tutti i compilatori testati (4 diverse architetture) che sostituiscono gli interi a larghezza fissa con i tipi fondamentali si è dimostrato soddisfacente per la mia situazione. Potrebbe essere necessario un aggiornamento in futuro, ma la maggior parte degli usi coinvolgerà un intero letterale. Risposta accettata –

0

Dal 7.20.1.1 standard di C11 (1)

Il nome typedef intN_t indica un tipo intero con segno con larghezza N, senza imbottitura bit, e la rappresentazione complemento a due. Quindi, int8_t indica un tipo intero con segno con una larghezza di esattamente 8 bit.

Quindi int32_t è un intero con segno che è esattamente largo 32 bit.

Un int se è definito come sizeof(int) essendo superiore o uguale ad un char (C++ 14 3.9.1 (2)) e che un int firmato deve essere in grado di rappresentare [-32767, 32767] (C11 5.2.4.2.1) . Tale intervallo è in realtà 16 bit.

Quindi uno int potrebbe non essere mai equivalente a intN_t come intN_t può essere un tipo definito di implementazione separato da un tipo standard.

+0

La larghezza del 'int' implementato non ha importanza, la paragono a tutte le varianti a larghezza fissa. Nessuna corrispondenza. –

Problemi correlati