Puntatori a Funzione[C]

Linguaggi di programmazione: php, perl, python, C, bash e tutti gli altri.
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Puntatori a Funzione[C]

Messaggio da gila75 »

Rieccomi ragazzi.... :D
Dopo lo studio delle liste, sto passando al capitolo puntatori a funzione.
A dire il vero, non colgo ancora le potenzialità rispetto alla chiamata a funzione normale.
Ma quello lo scoprirò col tempo.
Ho scritto un piccolo e rudimentale esempio, ma non mi tornano delle cose:

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
double prova(double *x,double *y)
{
    
    return (*x)+(*y);
}
    
         

int main(void)
{
    double x=3.14;
    double  y=6.28;
    double ris;
    double (*ptr)()=prova;
    ris=(*ptr)(&x,&y);
    printf ("ris = %lf\n",ris);
    return 0;
}
in questo punto

Codice: Seleziona tutto

  double (*ptr)()=prova;
Mi aspettavo di scrivere così, ma non funziona

Codice: Seleziona tutto

  double (*ptr)(double,double)=prova;
Perchè?

In un'altra discussione qui sul forum vengono trattati vari trucchi a riguardo, ma per ora è presto, ci arriverò poi.
Vorrei sapere se è corretto fare un puntatore a funzione come ho fatto sopra, e la domanda che ho già posto.
Grazie in anticipo
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: Puntatori a Funzione[C]

Messaggio da ixamit »

gila75 ha scritto: in questo punto

Codice: Seleziona tutto

  double (*ptr)()=prova;
Mi aspettavo di scrivere così, ma non funziona

Codice: Seleziona tutto

  double (*ptr)(double,double)=prova;
Perchè?

In un'altra discussione qui sul forum vengono trattati vari trucchi a riguardo, ma per ora è presto, ci arriverò poi.
Vorrei sapere se è corretto fare un puntatore a funzione come ho fatto sopra, e la domanda che ho già posto.
Grazie in anticipo
Si, non è una dichiarazione ma un assegnamento dell'indirizzo della funzione, abbastanza simile ai reference che gia' conosci.
L'utilizzo è di solito abbinato alle procedure che necessitano di callback parametrici. La qsort è un esempio

edit:

Codice: Seleziona tutto

double (*ptr)(double *, double *)=prova;
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Si, non è una dichiarazione ma un assegnamento dell'indirizzo della funzione, abbastanza simile ai reference che gia' conosci
Quindi sarebbe giusta la scrittura ?

Codice: Seleziona tutto

  double(*ptr)()=prova;
Se io scrivo

Codice: Seleziona tutto

double(*ptr)(double,double)=prova;
ottengo dal compilatore

Codice: Seleziona tutto

3d.c: In function ‘main’:
3d.c:16:33: warning: initialization from incompatible pointer type [enabled by default]
3d.c:17:5: error: incompatible type for argument 1 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
3d.c:17:5: error: incompatible type for argument 2 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
gila@ubuntu:~/Scrivania$ 



però in questo esempio

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
int prova(int x)
{
    x=x+100;
    return x;
}
     
     

int main(void)
{
    int a=19;
    int j;
    int (*ptr)(int)=prova;
    printf ("%d\n",j=(*ptr)(a));     
    return 0;
}
Tutto fila liscio è ho dichiarato il tipo

Codice: Seleziona tutto

 int (*ptr)(int)=prova;
Dov'è la differenza?
Presumo che nel primo esempio, ci sia qualcosa da modificare perchè vado al lavorare con gli indirizzi di x e y

Codice: Seleziona tutto

ris=(*ptr)(&x,&y);
Forse anche il compilatore me lo sta suggerendo, ma io non "colgo"

Codice: Seleziona tutto

3d.c:17:5: error: incompatible type for argument 1 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
3d.c:17:5: error: incompatible type for argument 2 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
Comunque ad ogni caso, è pratica errata lasciare vuota la parentesi o posso farlo?
La qsort è un esempio
Ci arriverò... :)
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: Puntatori a Funzione[C]

Messaggio da ixamit »

gila75 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4552652#p4552652][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
Si, non è una dichiarazione ma un assegnamento dell'indirizzo della funzione, abbastanza simile ai reference che gia' conosci
Quindi sarebbe giusta la scrittura ?

Codice: Seleziona tutto

  double(*ptr)()=prova;
Se io scrivo

Codice: Seleziona tutto

double(*ptr)(double,double)=prova;
ottengo dal compilatore

Codice: Seleziona tutto

3d.c: In function ‘main’:
3d.c:16:33: warning: initialization from incompatible pointer type [enabled by default]
3d.c:17:5: error: incompatible type for argument 1 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
3d.c:17:5: error: incompatible type for argument 2 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
gila@ubuntu:~/Scrivania$ 



però in questo esempio

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
int prova(int x)
{
    x=x+100;
    return x;
}
     
     

int main(void)
{
    int a=19;
    int j;
    int (*ptr)(int)=prova;
    printf ("%d\n",j=(*ptr)(a));     
    return 0;
}
Tutto fila liscio è ho dichiarato il tipo

Codice: Seleziona tutto

 int (*ptr)(int)=prova;
Dov'è la differenza?
Presumo che nel primo esempio, ci sia qualcosa da modificare perchè vado al lavorare con gli indirizzi di x e y

Codice: Seleziona tutto

ris=(*ptr)(&x,&y);
Forse anche il compilatore me lo sta suggerendo, ma io non "colgo"

Codice: Seleziona tutto

3d.c:17:5: error: incompatible type for argument 1 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
3d.c:17:5: error: incompatible type for argument 2 of ‘ptr’
3d.c:17:5: note: expected ‘double’ but argument is of type ‘double *’
Comunque ad ogni caso, è pratica errata lasciare vuota la parentesi o posso farlo?
La qsort è un esempio
Ci arriverò... :)
Se guardi, il post precedente c'è la correzione formale sul tuo esempio. L'errore dato in compilazione riguarda la definizione che risulta differente nella dichiarazione dei parametri (double è diverso da double *)

Quello che volevo chiarire che anche le funzioni sono puntatori, per cui è corretta (più o meno chiara) anche la prima forma.
Niente mi vieta di scrivere:

Codice: Seleziona tutto

...
void foo (int n, int z) 
{
   ....
}
..
int main ()
{
    ...
   void *x1 = foo; // OR ... = &foo
   void (*x2)()=foo;
    ...
}
x1 e x2 hanno gli stessi indirizzi, ma sono due puntatori differenti. . Ed anche (meno chiaramente ) si puo' "chiamare" foo con x1. Qui evito per ora l'esempio per non confonderti.
Avatar utente
matteovid
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 368
Iscrizione: mercoledì 9 dicembre 2009, 9:09
Desktop: Openbox, XFCE, XMonad
Distribuzione: GNU/Linux Arch - openSUSE Leap
Sesso: Maschile
Località: Parma

Re: Puntatori a Funzione[C]

Messaggio da matteovid »

se ho capito quello che chiedi Gila
io uso questo approccio :shy:

Codice: Seleziona tutto

#include <stdio.h>

/* tipi funzioni pointer */
typedef int (*sommafunz) (int, int);
typedef void (*stampafunz) (void);

int Somma(int , int );
void Stampa(void);

int main (int argc, char **argv)
{
  stampafunz a = &Stampa; /* a = pointer funz Stampa*/
  sommafunz b = &Somma; /* b = pointer funz Somma */
  int z = 32, v = 2;
  int x = (*b)(z, v); /* x = chiamo funz Somma pointer b */

  a(); /* a() = stampo messaggio, con chiamata funz Stampa*/

  printf ("%d + %d = %d\n", z, v, x); /* z, v, x */
  return (0);
}

int Somma(int u, int d) {
  return (u + d);
}

void Stampa(void) {
  printf("Somma di ");
}
miglia da percorrere, prima di dormire
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

ok, ho capito, grazie ixamit :)
Sono stato un po' un babbeo io, il compilatore lo diceva esplicitamente :D
Ma col senno di poi e quanto ti viene spiegato è tutto più semplice

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
double prova(double *x,double *y)
{
    
    return (*x)+(*y);
}
    
         

int main(void)
{
    double x=3.14;
    double  y=6.28;
    double ris;
    double (*ptr)(double*,double*)=prova;
    ris=(*ptr)(&x,&y);
    printf ("ris = %lf\n",ris);    
    return 0;
}
@matteovid

Mi sembra un po' più complesso il tuo metodo, devo digerirlo bene, comunque grazie anche a te.
Domanda: ma oltre al qsort, dove i puntatori a funzione vengono usati (devo ancora studiare però questa cosa), altri casi e vantaggi del puntatore a funzione ?
ixamit ha accennato, ma non ho capito bene. Poi logico, più vado avanti e più capirò, ma è più che altro una curiosità
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

Mi sembra un po' più complesso il tuo metodo
Le typedef vengono usate proprio per semplificare la vita,con la typedef dichiari un nuovo tipo(per modo di dire).
In questo modo non impazziszi con le dichiarazioni delle funzioni:
Classica:

Codice: Seleziona tutto


void fusaf( void (*unafunzione)(int,int) , int bho)
{...}

int main()
{
    ...
    void (*unafunzione)(int,int) = helloworldfunction;
}

come vedi il codice è complesso e lungo ed è un misero esempio.
Col typedef diventa:

Codice: Seleziona tutto


typedef void(*VOID_FNC_INT_INT)(int,int);

void fusaf( VOID_FNC_INT_INT fnz , int bho)
{...}

int main()
{
    ...
   VOID_FNC_INT_INT fnz = helloworldfunction;
}
Come vedi è tutto piu leggibile,e piu facile da utilizzare,infatti con le typedef viene poi anche generato un errore se non assegni il giusto tipo di funzione al proprio puntatore..
Le hai già studiate le typedef? Vengo stra usate anche per le liste.

L'utilizzo del puntatore a funzione è dei piu svariati,il già citato esempio della qsort.
Anche contenere Vettori di funzioni,prova ad immaginare un parser di comandi per console,prova a vederlo cosi:
- prendo in input una stringa
- converto il comando in un numero
- chiamo ptrfnc[idcmd](...)

Ma anche una sottospecie di programmazione ad oggetti:

Codice: Seleziona tutto

typedef void(*VERSO)(void);

typedef struct _ANIMALE
{
    char name[64];
    VERSO verso;
}ANIMALE;

typedef ANIMALE CANE;
typedef ANIMALE GATTO;
typedef ANIMALE* ANIMALI;

void miagola(){puts("Miao");}
void abbaia() {puts("Bau");}

#define NANIF 2

int main()
{
    CANE c;
         strcpy(c.name,"cane");
         c.verso = abbaia;
    GATTO g;
         strcpy(g.name,"gatto");
         g.verso = miagola;

    ANIMALI fattoria[NANIF];

    fattoria[0] = &c;
    fattoria[1] = &g;

    int i;
    for ( i = 0; i < NANIF; i++)
    {
        printf("%s:",fattoria[i]->name);
        fattoria[i]->verso();
    }

    return 0;
}

e in definitiva li puoi usare ovunque la tua mente ne concepisca il bisogno.
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Grazie vbextreme
Le hai già studiate le typedef? Vengo stra usate anche per le liste.
Si, ma (pessima cosa), non mi trovo molto bene.
Per esempio con le strutture se non usi typedef sei costretto a scrivere per esempio

struct node *p
Ricordandoti ogni volta che node è una struttura.
So che è sbagliato, ma faccio davvero fatica ad apprezzare typedf.
Altro esempio : dichiaro i tipi float come decimali (nome puramente di fantasia).
Trovo molto scomodo fare:
decimali a=3.5
Molto più chiaro
float a=3.5
Ma so che typedf è largamente usato, e allora o tutti sono "stupidi" e io intelligente o il contrario.
Propendo per la seconda ipotesi :D
Adesso provo a esercitarmi
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

@matteovid

Ho riscritto il codice da te postato, come l'avrei fatto io, cioè senza typedef.
Io lo trovo più semplice così, no?
Nudo e crudo: definisco le funzioni prima del main, creo i puntatori a funzione nel main, richiamo le funzioni
tramite i puntatori e stop.
Cosa c'è d'incasinato senza la typedef?
Non è un tono polemico logicamente, non vorrei essere frainteso, ma non capisco proprio
ecco:

Codice: Seleziona tutto

#include <stdio.h>
#include <stdlib.h>
int Somma(int *z,int *v)
{
    
    return (*z)+(*v);
}

void Stampa()
{
    printf("Somma di ");
    return;
    
}


int main(void)
{
    int z=32;
    int v=2;
    int ris;
    void (*ptr)(void)=Stampa;
    int  (*ptr_2)(int*,int*)=Somma;
    (*ptr)();
    ris=(*ptr_2)(&z,&v);
    printf ("%d + %d =%d\n",z,v, ris);
    return 0;
}
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: Puntatori a Funzione[C]

Messaggio da ixamit »

gila75 ha scritto: Si, ma (pessima cosa), non mi trovo molto bene.
Per esempio con le strutture se non usi typedef sei costretto a scrivere per esempio

struct node *p
Ricordandoti ogni volta che node è una struttura.
So che è sbagliato, ma faccio davvero fatica ad apprezzare typedf.
Consolati, sono in molti ad odiarle: Torvalds in primis
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: Puntatori a Funzione[C]

Messaggio da ixamit »

gila75 ha scritto:Domanda: ma oltre al qsort, dove i puntatori a funzione vengono usati (devo ancora studiare però questa cosa), altri casi e vantaggi del puntatore a funzione ?
Come gia' detto precedentemente, i puntatori a funzione vengono usati soprattutto nelle procedure di callback, cioè in tutti quei casi dove si necessita "chiamare" una funzione personalizzata e non una generica.
Ritornando brevemente suill' esempio della qsort: bisogna passare una funzione di comparazione personalizzata per il proprio tipo di elemento da trattare, cosi' che la funzione principale rimane slegata dal tipo di dato trattato, sia esso intero, stringa, struttura o quant'altro.

Altro esempio: nei toolkit di interfacce grafiche, quali Qt, GTK, ecc, gli eventi vengono catturati e rediretti verso la nostra funzione.
Che si chiamino segnali, eventi, callback o altro poco cambia.

Altri programmi e librerie fanno uso massiccio di puntatori a funzione. All'interno delle strutture trovi puntatori di inizializzazione,
di allocazione, di chiusura o altro che li rende maggiormente parametrici e adattabili alle piu' svariate circostanze.

In sintesi sono probabilmente la massima espressione parametrica del C, ma possono essere anche molto pericolosi in quanto non verificano l'oggetto referenziato o cosa potrebbe essere/fare. Quello che nei moderni linguaggi è piu' restrittivo qui' non lo e' affatto.
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

ixamit [url=http://forum.ubuntu-it.org/viewtopic.php?p=4553578#p4553578][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
gila75 ha scritto: Si, ma (pessima cosa), non mi trovo molto bene.
Per esempio con le strutture se non usi typedef sei costretto a scrivere per esempio

struct node *p
Ricordandoti ogni volta che node è una struttura.
So che è sbagliato, ma faccio davvero fatica ad apprezzare typedf.
Consolati, sono in molti ad odiarle: Torvalds in primis
Non so, mi sembra più ricamato e meno diretto usare typedf. Non ci trovo questo grande miglioramento in termini di leggibilità. Direi addirittura il contrario.
Ma ripeto, sono solo un principiante, ed è solo la mia opinione, non vorrei promuovere teorie sbagliate.

Per il resto, ho capito e ti ringrazio ixamit, passerò a capire come lavora la qsort.
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

Le typedef quando ben usate aiutano a comprendere meglio il codice.
Io ad esempio i nomi delle variabili li ho cosi:

Codice: Seleziona tutto

typedef char CHAR;
typedef unsigned char BYTE;
typedef short int INT16;
typedef unsigned short int UINT16;
typedef int INT32;
typedef unsigned int UINT32;
typedef long long INT64;
typedef unsigned long long UINT64;

typedef UINT16 WORD;
typedef UINT32 DWORD;
typedef UINT64 QWORD;
che a mio avviso è decisamente piu elegante e portabile che la classica dichiarazione delle variabili.
In piu "specifichi un nuovo tipo".
Ad esempio a mio avviso è piu chiara la lettura di un brano quale:

Codice: Seleziona tutto

...
DWORD func()
{...}
...
che molto probabilmente restituirà un flags rispetto alla piu canonica "unsigned int" che obbliga sempre ad avere il manuale sotto mano.
Ancora piu eclatante con l'uso dei puntatori.
(esempio inventato non sono al mio pc)

Codice: Seleziona tutto

typedef void* CONTROL
...
CONTROL a = cntrl_new("BUTTON");
...
Sono piccole accortezze che ne migliorano la leggibilità,un pò come i commenti che spesso i programmatori si dimenticano di aggiungere.
Io molto probabilmente ne abuso,ma sicuramente un buon compromesso è sempre ben accetto.
Poi sai che noia dover riscrivere 100 volte lo stesso prototipo della stessa funzione di callback?
Easy framework per il linguaggio C.
vbextreme hack your life
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

vbextreme [url=http://forum.ubuntu-it.org/viewtopic.php?p=4553695#p4553695][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Le typedef quando ben usate aiutano a comprendere meglio il codice.
Io ad esempio i nomi delle variabili li ho cosi:

Codice: Seleziona tutto

typedef char CHAR;
typedef unsigned char BYTE;
typedef short int INT16;
typedef unsigned short int UINT16;
typedef int INT32;
typedef unsigned int UINT32;
typedef long long INT64;
typedef unsigned long long UINT64;

typedef UINT16 WORD;
typedef UINT32 DWORD;
typedef UINT64 QWORD;
che a mio avviso è decisamente piu elegante e portabile che la classica dichiarazione delle variabili.
In piu "specifichi un nuovo tipo".
Ad esempio a mio avviso è piu chiara la lettura di un brano quale:

Codice: Seleziona tutto

...
DWORD func()
{...}
...
che molto probabilmente restituirà un flags rispetto alla piu canonica "unsigned int" che obbliga sempre ad avere il manuale sotto mano.
Ancora piu eclatante con l'uso dei puntatori.
(esempio inventato non sono al mio pc)

Codice: Seleziona tutto

typedef void* CONTROL
...
CONTROL a = cntrl_new("BUTTON");
...
Sono piccole accortezze che ne migliorano la leggibilità,un pò come i commenti che spesso i programmatori si dimenticano di aggiungere.
Io molto probabilmente ne abuso,ma sicuramente un buon compromesso è sempre ben accetto.
Poi sai che noia dover riscrivere 100 volte lo stesso prototipo della stessa funzione di callback?
Credo sia importante il dicorso su typedef, anche se non è prettamente l'argomento della discussione, quindi parliamone un pò.
Quello che hai scritto sopra, è vero vbextreme, però a mio avviso, tu definisci:

Codice: Seleziona tutto

typedef short int INT16;
typedef unsigned short int UINT16;
per te, è logico e sensato definire così i vari tipi, e devo dire che che in effetti hanno un senso i nuovi tipi che tu hai "inventato".
Ma non è detto che per altri sia così no?
Non ne risente la leggibilità?
Non si obbliga un altro utente ogni volta a tornare in cima al programma per vedere cosa è per esempio INT16?
Logicamente per te è naturale e scontato, ma magari per me o altri no.
Se io studio il C, qualcosina a memoria dovrò pur ricordare no?
Quindi float e double (se ho un minimo di rudimenti in C) mi dovrebbero subito balzare all'occhio.
Lo stesso discorso lo facevo per le strutture.
Scrivere struct node*p è vero che ogni volta hai la rottura di scrivere "struct", ma è immediato e sai cosa stai trattando.
Poi sai che noia dover riscrivere 100 volte lo stesso prototipo della stessa funzione di callback?
Qui, posso essere d'accordo.

L'esempio che ha fatto Matteovid, è funzionante e perfetto ,ma io mi trovo meglio con l'esempio che ho postato io, lo trovo più semplice.
Se non erro poi il typedef, è di recente introduzione nel C, giusto.
Magari recente no, ma agli arbori, mi pare di aver letto che non esisteva.
antex
Prode Principiante
Messaggi: 85
Iscrizione: mercoledì 14 marzo 2012, 20:59

Re: Puntatori a Funzione[C]

Messaggio da antex »

gila75 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4553709#p4553709][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:
vbextreme [url=http://forum.ubuntu-it.org/viewtopic.php?p=4553695#p4553695][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Le typedef quando ben usate aiutano a comprendere meglio il codice.
Io ad esempio i nomi delle variabili li ho cosi:

Codice: Seleziona tutto

typedef char CHAR;
typedef unsigned char BYTE;
typedef short int INT16;
typedef unsigned short int UINT16;
typedef int INT32;
typedef unsigned int UINT32;
typedef long long INT64;
typedef unsigned long long UINT64;

typedef UINT16 WORD;
typedef UINT32 DWORD;
typedef UINT64 QWORD;
....
Credo sia importante il dicorso su typedef, anche se non è prettamente l'argomento della discussione, quindi parliamone un pò.
Quello che hai scritto sopra, è vero vbextreme, però a mio avviso, tu definisci:

Codice: Seleziona tutto

typedef short int INT16;
typedef unsigned short int UINT16;
per te, è logico e sensato definire così i vari tipi, e devo dire che che in effetti hanno un senso i nuovi tipi che tu hai "inventato".
Ma non è detto che per altri sia così no?
Non ne risente la leggibilità?
Non si obbliga un altro utente ogni volta a tornare in cima al programma per vedere cosa è per esempio INT16?
Logicamente per te è naturale e scontato, ma magari per me o altri no.
UINT16 dice esattamente di che tipo si tratta. Credo tra l'altro che sia una definizione fatta in qualche header in Windows. Dai un'occhiata ai tipi definiti in stdint.h, che come dice il nome sono standard (C99): uint8_t int16_t uint32_t int64_t & Co. Se stai implementando una struttura dati che ha bisogno di 16 bit, molto probabilmente ti converrà usare un uint16_t, perché in questo modo sei sicuro che quell'oggetto sarà a 16 bit indipendentemente dall'architettura hardware (non hai la garanzia che uno short sia 16 bit o che un long sia 64 bit). È essenziale il typedef? No, in questo caso no, e infatti UINT16, DWORD e simili potrebbero essere semplicemente delle macro (#define). Però typedef ti facilita se vuoi aggiungere un minimo di type-safety:

Codice: Seleziona tutto

/* 
 * Type-safe byteorder definitions.
 */
typedef struct { uint16_t v; } le16_t;
typedef struct { uint16_t v; } be16_t;
(cerca byteorder.h). Se dichiari be16_t da qualche parte (e non struct be16_t, che sarebbe proprio brutto :nono: ), diventa esplicito che hai un intero memorizzato in formato big-endian e in più, trattandosi di strutture, il compilatore ti fa dei controlli appositi (così non passi un little-endian a una funzione che richiede un big-endian, per esempio).
Se io studio il C, qualcosina a memoria dovrò pur ricordare no?
Quindi float e double (se ho un minimo di rudimenti in C) mi dovrebbero subito balzare all'occhio.
Ma infatti non bisogna abusare dei typedef, sennò si riduce solamente la leggibilità.
Se non erro poi il typedef, è di recente introduzione nel C, giusto.
Magari recente no, ma agli arbori, mi pare di aver letto che non esisteva.
Agli "albori" forse no, ma già il C89 prevedeva il typedef: più indietro di quello è la "preistoria". :D
gila75
Imperturbabile Insigne
Imperturbabile Insigne
Messaggi: 2739
Iscrizione: mercoledì 16 gennaio 2013, 17:28
Desktop: ubuntu-2d
Distribuzione: Ubuntu 12.04.2 LTS i686
Località: Airuno(Lecco)

Re: Puntatori a Funzione[C]

Messaggio da gila75 »

Grazie antex, però in riferimento ai due esempi, il mio e quello di mettoevid, non risulta molto più semplice il mio codice che non usa typedef?
è solo una domanda, non voglio certo screditare matteovid...anzi, lo ringrazio.
Ma in quel caso, mi sembra che si facciano dei "giri" in più utilizzando typedef.
Vorrei capire in riferimento a quel caso per ora...poi cercherò di utilizzarlo, anche se davvero, non mi garba molto.
antex
Prode Principiante
Messaggi: 85
Iscrizione: mercoledì 14 marzo 2012, 20:59

Re: Puntatori a Funzione[C]

Messaggio da antex »

gila75 [url=http://forum.ubuntu-it.org/viewtopic.php?p=4553802#p4553802][img]http://forum.ubuntu-it.org/images/icons/icona-cita.gif[/img][/url] ha scritto:Grazie antex, però in riferimento ai due esempi, il mio e quello di mettoevid, non risulta molto più semplice il mio codice che non usa typedef?
è solo una domanda, non voglio certo screditare matteovid...anzi, lo ringrazio.
Ma in quel caso, mi sembra che si facciano dei "giri" in più utilizzando typedef.
Vorrei capire in riferimento a quel caso per ora...poi cercherò di utilizzarlo, anche se davvero, non mi garba molto.
Ti riferisci all'uso con puntatori a funzione? Per questo il typedef è già meno diffuso, non mi vengono in mente grosse librerie che lo impiegano sistematicamente (ma magari ci sono). Per esempio, se fosse usato in una libreria per definire il tipo di una callback, sarebbe utile non tanto a te che implementi la callback (perché comunque devi conoscere esattamente la firma della funzione), ma piuttosto per chi scrive la libreria ai fini della documentazione (definisce il tipo della callback, che magari si usa svariate volte come parametro di funzioni della libreria, e lo documenta a parte).

Il typedef con puntatori a funzione ti può facilitare se stai scrivendo un tuo codice e per qualche motivo hai a che fare con prototipi di funzioni piuttosto complesse; allora ti può venire più comodo usare typedef per non incasinarti con le parentesi. Ma non è che sia appassionatamente da consigliare. :)
Avatar utente
vbextreme
Entusiasta Emergente
Entusiasta Emergente
Messaggi: 1214
Iscrizione: domenica 12 gennaio 2014, 14:06
Desktop: lxde
Distribuzione: xubuntu 14.10

Re: Puntatori a Funzione[C]

Messaggio da vbextreme »

UINT16 dice esattamente di che tipo si tratta. Credo tra l'altro che sia una definizione fatta in qualche header in Windows
esatto,quindi con una bella #ifdef posso stabilire se includere l'header di windows o il mio non modificando il codice ed usando la stessa tipologia di parametri.
Ma non è detto che per altri sia così no?
Come ho già ripetuto è tutto molto personale,e per me che sbalzo da windows a linux è piu semplice usare quella tipologia rispetto al classico int,come lo sarà per tutti quelli che fanno come me e altresi sarà piu complicato per chi conosce solo linux.Da notare comunque che la dicitura INT16 è molto incisiva,mica crederai che siano 16 interi?
Non si obbliga un altro utente ogni volta a tornare in cima al programma per vedere cosa è per esempio INT16?
No ed è proprio lo scopo delle typedef ed altre strategie.
Generalmente uno legge il reference e poi inizia a programmare,ma se non hai niente che ti aiuti dovrai sempre ritirare fuori il manuale per guardarti cosa fa quella determinata funzione.
Ad esempio il prototipo:

Codice: Seleziona tutto

char* strcpy(char* ,const char*);
è molto esplicito,e a mio avviso quel const non è stato messo li tanto per la sicurezza ma piu che altro per capire al volo cosa fa la funzione.Il nome copia stringa mi lascia capire che copio due vettori di caratteri,ma qual'è il source e il dest? ovvio quello col const non lo posso modificare e quindi sarà per forza il source e l'altro il dest.

Torniamo alla typedef con i puntatori a funzione.

Codice: Seleziona tutto

int newtimer(const int,void(*tmrprc)(int,int,int,int));
Cosa capiresti di una funzione cosi?
e se la riscrivo cosi:

Codice: Seleziona tutto

HANDLE newtimer(const INT32,CALLBACKTIMER fnc);
nel secondo esempio è facile capire che la funzione restituisce un valore che identifica il timer e gli debbo passare un intero costante che si presupponga sia l'intervallo e una funzione di callback usata dal timer.
Come noterai sia il primo esempio che il secondo obbligano nel dover conoscere la funzione di callback cosa faccia.Solo che il secondo è piu significativo almeno per uno che abbia già letto il reference ma non si ricordi bene che parametri richieda la funzione.(Ricordo che tutti gli ide aiutano col visualizzare il prototipo di una funzione,cosa importantissima perchè io ad esempio non ho molta memoria e ricordarmi 10000 tipi di funzioni non ce la faccio.)

ecco un frammento dell'header che gestisce i miei thread sotto linux,(__THR è definito nel file .c e non nell'header in modo da essere offuscato)

Codice: Seleziona tutto

typedef struct __THR* THR;
typedef PVARIANT (*THRCALL)(PVARIANT);
THR thr_new(THRCALL thrcall,UINT32 stksz,WORD runsuspend);
sotto windows mi basterà modificare solo il puntatore della funzione ovvero:

Codice: Seleziona tutto

typedef DWORD(*THRCALL)(PVARIANT)
Come vedi le typedef sono obbligatorie in questo caso anche con le strutture perchè THR è si una struttura però non posso accedervi e pertanto è stilisticamente orrendo scrivere "struct __THR*" e poi sapere che non vi si può accedere.

Non sei obbligato ad usarle,volevo solo accennartele,vedrai che tanto piu avanti le amerai.
Easy framework per il linguaggio C.
vbextreme hack your life
ixamit
Scoppiettante Seguace
Scoppiettante Seguace
Messaggi: 499
Iscrizione: giovedì 14 novembre 2013, 10:16

Re: Puntatori a Funzione[C]

Messaggio da ixamit »

vbexteme ha scritto: ... [continua]...

Ad esempio il prototipo:

Codice: Seleziona tutto

char* strcpy(char* ,const char*);
è molto esplicito,e a mio avviso quel const non è stato messo li tanto per la sicurezza ma piu che altro per capire al volo cosa fa la funzione.Il nome copia stringa mi lascia capire che copio due vettori di caratteri,ma qual'è il source e il dest? ovvio quello col const non lo posso modificare e quindi sarà per forza il source e l'altro il dest.
Vabbè, qui' stiamo andando OT di brutto... e ci sarebbe molto da dire. Limitiamoci a dire che il prototype puo' essere definito meglio.
vbextreme ha scritto: Torniamo alla typedef con i puntatori a funzione.

Codice: Seleziona tutto

int newtimer(const int,void(*tmrprc)(int,int,int,int));
Cosa capiresti di una funzione cosi?
e se la riscrivo cosi:

Codice: Seleziona tutto

HANDLE newtimer(const INT32,CALLBACKTIMER fnc);
nel secondo esempio è facile capire che la funzione restituisce un valore che identifica il timer e gli debbo passare un intero costante che si presupponga sia l'intervallo e una funzione di callback usata dal timer.
Il mio punto di vista e' differente perche' a mio avviso e' di gran lunga piu' esplicativo il primo. E qui leggo chiaramente:
dichiarazione della funzione newTimer che ritorna un intero, passa un intero ed un puntatore a funzione con 4 parametri interi (anche qui' come sopra si poteva dettagliare con dei nomi). Mi sembra chiaro, nessuna ambiguita'se non nello specifico della tmrpcr stessa.

Mentre nel secondo caso non so cosa sia HANDLE (puo' essere benissimo un puntatore a struttura) e CALLBACKTIMER (dal nome immagino sia un puntatore a funzione) non so quanti parametri accetta e neanche cosa restituisce, se non andando a leggermi precedente il typedef.

E' anche vero che la seconda forma in certi aspetti è meglio della prima, ma non tanto per la definizione della CALLBACKTIMER,
ma per HANDLE (dipende comunque dal contesto, ma sicuramente un upgrade della newtimer potrebbe essere meno indolore).

Detto questo, non vedo in un contesto aperto particolari linee guida,; c'e' chi preferisce in un modo, chi nell'altro.
antex
Prode Principiante
Messaggi: 85
Iscrizione: mercoledì 14 marzo 2012, 20:59

Re: Puntatori a Funzione[C]

Messaggio da antex »

vbextreme ha scritto:
UINT16 dice esattamente di che tipo si tratta. Credo tra l'altro che sia una definizione fatta in qualche header in Windows
esatto,quindi con una bella #ifdef posso stabilire se includere l'header di windows o il mio non modificando il codice ed usando la stessa tipologia di parametri.
Oppure puoi usare direttamente le versioni standard (stdint.h), se non hai una versione troppo vecchia di Visual Studio.
ecco un frammento dell'header che gestisce i miei thread sotto linux,(__THR è definito nel file .c e non nell'header in modo da essere offuscato)

Codice: Seleziona tutto

typedef struct __THR* THR;
...
...
Ecco, dato che si parla di typedef, mi sembra giusto far notare che questa è una cosa che in generale va evitata: nascondere un puntatore dentro una typedef. In questo caso, però, riconosco che ci sta, dato che THR è concepito come un "handle" (cioè opaco).

Faccio un altro esempio, per certi versi opposto a:
vbextreme ha scritto:

Codice: Seleziona tutto

typedef void(*VOID_FNC_INT_INT)(int,int);

void fusaf( VOID_FNC_INT_INT fnz , int bho)
{...}

...
Più typedef per funzioni con la stessa firma:

Codice: Seleziona tutto

/**
 * Bla bla bla.
 * @param a The first element to be compared.
 * @param b The second element to be compared.
 * @return The result of the comparison, bla bla bla, -1 if bla, 0 if equal, greater than 0 if bla.
 */
typedef int (*comparer)(int a, int b);

/**
 * Bla bla bla.
 * @param acc The current aggregated value.
 * @param b The element to be aggregated.
 * @return The result of the aggregation of @c value to @c acc.
 */
typedef int (*accumulator)(int acc, int value);
Potrebbero essere utili perché a questo punto posso fare:

Codice: Seleziona tutto

/**
 * Bla bla.
 * @param acc The accumulator function. @see #accumulator
 */
int accumulate(int v[], int length, accumulator acc) {
    ...
}

Codice: Seleziona tutto

/**
 * Quick sort.
 * @param acc The comparison function. @see #comparer
 */
void qsort(int v[], int length, comparer comp) {
    ...
}

/**
 * Bla bla sort.
 * @param acc The comparison function. @see #comparer
 */
void bsort(int v[], int length, comparer comp) {
    ...
}
Scrivi risposta

Ritorna a “Programmazione”

Chi c’è in linea

Visualizzano questa sezione: 0 utenti iscritti e 2 ospiti