DOMANDA Come dichiarare una variabile valida sia come int,float,double.

stex99.

Nuovo Utente
6
1
Sto creando una libreria in linguaggio C
Dopo aver creato il file con estensione .h ho inserito i prototipi delle mie funzioni.
Poi mi sono domandato:
Voglio creare una funzione che faccia la somma di due numeri inseriti dunque io scrivo come prototipo:
void spinaci (double, double);
dunque mi pare chiaro che se dovessi usarla inserendo però variabili di tipo int potrebbe non funzionare.
viceversa se dovessi dichiarare un prototipo del tipo:

void spinaci (int, int);
e poi usare variabili di tipo double.


Ecco, potrei fare un cambio di tipologia di variabile nei futuri programmi che scriverò (tipo trasformo variabili di tipo double in int...se possibile… o viceversa), oppure creo più funzioni (spinaci1 spinaci2...) ciascuna con una diversa scelta dell'argomento. In entrambi i casi è piuttosto scomodo.
Mi chiedo come posso generalizzare la cosa, ossia definire una tipologia di variabile che vada d'accordo con tutte quelle che uso nei miei corsi universitari (int, double, float).
che faccio?
 

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Eheh. In C++ esiste l’overload di una funzione, per non parlare dei conseguenti Template.
In C ti crei manualmente tu le funzioni che ti servono. Certo che un intero è tranquillamente un float e un float è tranquillamente un double perciò puoi usare double per tutti.
 
  • Mi piace
Reazioni: stex99.

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,223
1,854
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Eh, stai toccando uno degli aspetti dolenti del C: non ci sono tipi generici.
Ovviamente puoi memorizzare un int in un double, in quanto la parte decimale verrebbe troncata (perdendo quindi l'informazione).

Oltre a duplicare il codice, e duplicare quindi le funzioni come suggerito da _Achille, rendendole però magari accessibili utilizzando lo stesso nome, e quindi decidere durante l'esecuzione quale chiamare, puoi sfruttare il preprocessore e lasciare a lui la scrittura delle diverse tipologie di funzioni...

Ho ipotizzato il calcolo della media di N valori (4 nel mio caso, per semplicità); non effettuo controlli sulla prima posizione dell'array, essendo solo un esempio.

C:
//
// name: templates.h
//

#define CONCAT(x, y) x ## y

#define get_average(T) CONCAT(get_average_, T)

TYPE get_average (TYPE) (TYPE * array, int len)
{
    TYPE sum = array[0];
    for(int i=0; i<len; i++)
        sum += array[i];
   
    return sum / len;
}

Uso la concatenazione dei token (quel ## sulla prima macro), nota anche come "token pasting". In sostanza concatena due token validi. Quindi l'altra macro, get_average, forma quello che è il nome completo della funzione, ad esempio: get_average_int, get_average_double etc etc.

C:
//
// main.c
//
#include<stdio.h>

#define TYPE int
#include "templates.h"
#undef TYPE

#define TYPE double
#include "templates.h"
#undef TYPE


int main()
{
    int    int_array[]    = {10,20,40,50};
    double double_array[] = {10.5, 20.5, 30.5, 33.5};
   
    int    avg_int    = get_average(int)(int_array, 4);
    double avg_double = get_average(double)(double_array, 4);
   
    printf("Media ints: %d\n", avg_int);
    printf("Media doubles: %f\n", avg_double);

    return 0;
}

Output:
Codice:
Media ints: 32
Media doubles: 26.375000

Dopo svariate correzioni, analizzando il preprocessore, sono riuscito a far funzionare qualcosa. Da notare comunque che nel sorgente è necessario includere l'header più volte impostando un TYPE differente.

Questo è il codice dopo l'espansione (è necessario compilare con gcc -E nome_file.c):
C:
# 5 "templates.h"
int get_average_int (int * array, int len)
{
    int sum = array[0];
    for(int i=0; i<len; i++)
        sum += array[i];

    return sum / len;
}
# 5 "generic.c" 2



# 1 "templates.h" 1




double get_average_double (double * array, int len)
{
    double sum = array[0];
    for(int i=0; i<len; i++)
        sum += array[i];

    return sum / len;
}
# 9 "generic.c" 2



int main()
{
    int int_array[] = {10,20,40,50};
    double double_array[] = {10.5, 20.5, 30.5, 33.5};

    int avg_int = get_average_int(int_array, 4);
    double avg_double = get_average_double(double_array, 4);

    printf("Media ints: %d\n", avg_int);
    printf("Media doubles: %f\n", avg_double);

    return 0;
}
 
  • Mi piace
Reazioni: stex99.

Ci sono discussioni simili a riguardo, dai un'occhiata!

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili