In che misura andare con typedef'ing tipi primitivi come int

13

Ho visto codice C ++ come il seguente con molti typedef s.

Quali sono i vantaggi dell'utilizzo di molti typedef s come questo anziché utilizzare le primitive C ++? C'è un altro approccio che potrebbe anche raggiungere quei benefici?

Alla fine, i dati sono tutti archiviati in memoria o trasmessi via cavo come bit e byte, è davvero importante?

types.h:

typedef int16_t Version;
typedef int32_t PacketLength;
typedef int32_t Identity;
typedef int32_t CabinetNumber;
typedef int64_t Time64;
typedef int64_t RFID;
typedef int64_t NetworkAddress;
typedef int64_t PathfinderAddress;
typedef int16_t PathfinderPan;
typedef int16_t PathfinderChannel;
typedef int64_t HandsetSerialNumber;
typedef int16_t PinNumber;
typedef int16_t LoggingInterval;
typedef int16_t DelayMinutes;
typedef int16_t ReminderDelayMinutes;
typedef int16_t EscalationDelayMinutes;
typedef float CalibrationOffset;
typedef float AnalogValue;
typedef int8_t PathfinderEtrx;
typedef int8_t DampingFactor;
typedef int8_t RankNumber;
typedef int8_t SlavePort;
typedef int8_t EventLevel;
typedef int8_t Percent;
typedef int8_t SensorNumber;
typedef int8_t RoleCode;
typedef int8_t Hour;
typedef int8_t Minute;
typedef int8_t Second;
typedef int8_t Day;
typedef int8_t Month;
typedef int16_t Year;
typedef int8_t EscalationLevel;

Sembra logico cercare di assicurarsi che lo stesso tipo sia sempre usato per una cosa particolare per evitare gli overflow, ma spesso vedo il codice dove "int" è stato usato praticamente ovunque. Il typedef ing porta spesso al codice che sembra un po 'come questo:

DoSomething(EscalationLevel escalationLevel) {
    ...
}

Quindi mi chiedo quale token stia effettivamente descrivendo il parametro: il tipo di parametro o il nome del parametro?

    
posta Mark 20.06.2011 - 12:00
fonte

7 risposte

13

Il nome di un parametro dovrebbe descrivere cosa significa - nel tuo caso il livello di escalation. Il tipo è come viene rappresentato il valore - aggiungendo typedef come nel tuo esempio offusca questa parte della firma della funzione, quindi non la consiglierei.

I typedef sono utili per i modelli o se si desidera modificare il tipo utilizzato per determinati parametri, ad esempio durante la migrazione da una piattaforma a 32 bit a 64 bit.

    
risposta data 20.06.2011 - 12:03
fonte
17

All'inizio pensavo "Why not" ma poi mi è venuto in mente che se hai intenzione di andare così lontano per separare i tipi in quel modo, allora usa meglio la lingua. Invece di usare alias, in realtà definisci i tipi:

class AnalogueValue
{
public:
    // constructors, setters, getters, etc..
private:
    float m_value;
};

Non c'è differenza di prestazioni tra:

typedef float AnalogueValue;
AnalogValue a = 3.0f;
CallSomeFunction (a);

e

AnalogValue a (3.0f); // class version
CallSomeFunction (a);

e hai anche i vantaggi di aggiungere la convalida dei parametri e digitare sicurezza. Ad esempio, considera il codice che tratta il denaro usando i tipi primitivi:

float amount = 10.00;
CallSomeFunction(amount);

Oltre ai problemi di arrotondamento, consente anche qualsiasi tipo che può essere convertito in un float:

int amount = 10;
CallSomeFunction(amount);

In questo caso non è un grosso problema, ma le conversioni implicite possono essere una fonte di bug che è difficile da definire. L'utilizzo di typedef non aiuta qui, poiché sono semplicemente un alias di tipo.

L'uso di un nuovo tipo significa che non ci sono conversioni implicite a meno che non si codifichi un operatore di casting, che è una cattiva idea in particolare perché consente conversioni implicite. Puoi anche incapsulare dati aggiuntivi:

class Money {
  Decimal amount;
  Currency currency;
};

Money m(Decimal("10.00"), Currency.USD);
CallSomeFunction(m);

Nient'altro si adatterà a tale funzione a meno che non scriviamo codice per farlo accadere. Le conversioni accidentali sono impossibili. Possiamo anche scrivere tipi più complessi, se necessario, senza troppi problemi.

    
risposta data 20.06.2011 - 12:14
fonte
3

L'uso di typedef per tipi primitivi come quello sembra più come il codice di stile C.

In C ++ riceverai errori interessanti non appena proverai a sovraccaricare le funzioni per, diciamo, EventLevel e Hour . Ciò rende abbastanza inutili i nomi dei tipi extra.

    
risposta data 20.06.2011 - 12:48
fonte
2

Noi (nella nostra azienda) lo facciamo molto in C ++. Aiuta a comprendere e mantenere il codice. Il che è buono quando si spostano le persone tra le squadre o si fa il refactoring. Esempio:

typedef float Price;
typedef int64_t JavaTimestmap;

void f(JavaTimestamp begin, JavaTimestamp end, Price income);

Riteniamo che sia una buona pratica creare typedef per il nome della dimensione dal tipo di rappresentazione. Questo nuovo nome rappresenta un ruolo generale in un software. Il nome di un parametro è un ruolo locale . Mi piace in User sender, User receiver . In alcuni punti può essere ridondante, come void register(User user) , ma non ritengo che sia un problema.

Più tardi si potrebbe avere l'idea che float non sia il migliore per rappresentare i prezzi a causa delle speciali regole di arrotondamento della prenotazione, quindi si scarica o implementa un BCDFloat (codice binario decimale) e cambia il typedef. Non ci sono ricerche e sostituisci il lavoro da float a BCDFloat che sarebbe rafforzato dal fatto che ci sono probabilmente molti altri float nel tuo codice.

Non è un proiettile d'argento e ha i suoi avvertimenti, ma pensiamo che sia molto meglio usarlo che non.

    
risposta data 13.10.2015 - 16:47
fonte
1

typedef consente in sostanza di fornire un alias per un type .
Ti dà la flessibilità di evitare di digitare il lungo type names ancora e ancora e rendere il type più facilmente leggibile in cui il nome alias indica l'intento o lo scopo del type .

È più una questione di scelta se desideri avere nomi più leggibili attraverso typedef nel tuo progetto.
Di solito, evito di usare typedef sui tipi primitivi, a meno che non siano insolitamente lunghi da digitare. Tengo i miei nomi dei parametri più indicativi.

    
risposta data 20.06.2011 - 12:03
fonte
0

Non farei mai qualcosa di simile. Assicurati che tutti abbiano le stesse dimensioni è una cosa, ma devi solo fare riferimento ad essi come tipi interi, quindi.

    
risposta data 20.06.2011 - 12:03
fonte
0

L'uso di typedef come questo è ok, a patto che chiunque li usi non ha bisogno di sapere nulla della loro rappresentazione sottostante . Ad esempio, se desideri passare un oggetto PacketLength a printf o scanf , dovrai conoscere il suo tipo effettivo in modo da poter scegliere il giusto identificatore di conversione. In casi come questo, il typedef aggiunge solo un livello di offuscamento senza comprare nulla in cambio; potresti anche aver appena definito l'oggetto come int32_t .

Se è necessario applicare la semantica specifica a ciascun tipo (come intervalli o valori consentiti), è meglio creare un tipo di dati e funzioni astratti per operare su quel tipo, piuttosto che creare semplicemente un typedef.

    
risposta data 20.06.2011 - 20:41
fonte

Leggi altre domande sui tag