Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Lenovo ThinkVision 3D 27, la steroscopia senza occhialini
Lenovo ThinkVision 3D 27, la steroscopia senza occhialini
Primo contatto con il monitor Lenovo ThinkVision 3D 27 che grazie a particolari accorgimenti tecnici riesce a ricreare l'illusione della spazialità tridimensionale senza che sia necessario utilizzare occhialini
La Formula E può correre su un tracciato vero? Reportage da Misano con Jaguar TCS Racing
La Formula E può correre su un tracciato vero? Reportage da Misano con Jaguar TCS Racing
Abbiamo visto ancora una volta la Formula E da vicino, ospiti di Jaguar TCS Racing. In questa occasione però curve e rettilinei erano quelli di un circuito permanente, molto diverso dagli stretti passaggi delle strade di Roma
Lenovo LEGION e LOQ: due notebook diversi, stessa anima gaming
Lenovo LEGION e LOQ: due notebook diversi, stessa anima gaming
Lenovo ha puntato forte sul gaming negli ultimi anni e lo testimoniano i marchi LEGION e LOQ, il primo per gli amanti delle massime prestazioni e dell'assenza di compromessi, il secondo per chi desidera soluzioni dal buon rapporto tra prestazioni e prezzo. Abbiamo provato due esponenti dell'offerta, così da capire l'effettiva differenza prestazionale.
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 27-04-2020, 09:25   #1
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
C curiosità sui puntatori

se uso una variabile globale del tipo:

char *pippo;

e poi la uso in una funzione senza parametri nella quale ne incremento l'indirizzo, quando ritorno al chiamante mi ritrovo con la variabile pippo che punta ad un nuovo indirizzo.

Se invece costruisco una funzione dove come parametro passo proprio quel puntatore e lo incremento, al ritorno pippo è come se non si fosse mossa: è normale questo funzionamento?

Riassumendo: (attenzione, codice non testato e magari zeppo di errori)

Codice:
char *pippo;

main()
{
	pluto();
}

void pluto()
{
	pippo++;
}
// ------------------------------------------
char *pippo;
int pluto(char *pippo);

main()
{
	pluto(pippo);
}

int pluto(char *pippo)
{
	return pippo++;
}

Ultima modifica di misterx : 27-04-2020 alle 12:30.
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 27-04-2020, 12:57   #2
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
risolto ho preso un abbaglio
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 27-04-2020, 21:22   #3
Lampo89
Member
 
L'Avatar di Lampo89
 
Iscritto dal: Dec 2006
Messaggi: 33
Ciao,

Quote:
Originariamente inviato da misterx Guarda i messaggi
se uso una variabile globale del tipo:

char *pippo;

e poi la uso in una funzione senza parametri nella quale ne incremento l'indirizzo, quando ritorno al chiamante mi ritrovo con la variabile pippo che punta ad un nuovo indirizzo.

Se invece costruisco una funzione dove come parametro passo proprio quel puntatore e lo incremento, al ritorno pippo è come se non si fosse mossa: è normale questo funzionamento?

Riassumendo: (attenzione, codice non testato e magari zeppo di errori)

Codice:
char *pippo;

main()
{
	pluto();
}

void pluto()
{
	pippo++;
}
// ------------------------------------------
char *pippo;
int pluto(char *pippo);

main()
{
	pluto(pippo);
}

int pluto(char *pippo)
{
	return pippo++;
}
sì è corretto come da specifiche. Nel primo caso hai appunto definito una variabile globale che è visibile anche in tutte le translation units grazie alla magica magia del linker. Nel secondo caso, vale la semantica pass-by-value solita: alla chiamata di una funzione viene creato un nuovo stack frame in cui sono copiati il valore dei parametri passati.
Morale della favola: meglio evitare, se possibile, variabili globali ...
Lampo89 è offline   Rispondi citando il messaggio o parte di esso
Old 28-04-2020, 07:29   #4
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
però ho idea di non avere alternative all'uso di una variabile globale per via della storia del passaggio per valore e non per riferimento.
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 28-04-2020, 11:48   #5
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
approfitto di questo mia 3d per chiedervi:

se voglio sapere se l'MSB è settato, mi basta nel caso di un byte verificare che il suo valore sia < 128.
Tutti quelli maggiori o uguali hanno l'MSB settato a 1, ma perchè molti invece usano questa forma?

byte miobyte = 129;
byte MSB = (miobyte >> 7) & 1;
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 28-04-2020, 18:21   #6
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2745
Quote:
Originariamente inviato da misterx Guarda i messaggi
però ho idea di non avere alternative all'uso di una variabile globale per via della storia del passaggio per valore e non per riferimento.
Invece di passare il valore della variabile, puoi passare l'indirizzo della variabile
Esempio:

Codice:
main()
{
	char *pippo;
	//... pippo viene inizializzato in qualche modo
	pluto(&pippo);
	//giunti qui pippo è stato incrementato di 1
}

int pluto(char **pippo)
{
	(*pippo)++;
}
Ho messo le parentesi in (*pippo)++; perché non ricordo la precedenza degli operatori, nel dubbio con le parentesi non ci sono equivoci.
Quote:
Originariamente inviato da misterx Guarda i messaggi
approfitto di questo mia 3d per chiedervi:

se voglio sapere se l'MSB è settato, mi basta nel caso di un byte verificare che il suo valore sia < 128.
Tutti quelli maggiori o uguali hanno l'MSB settato a 1, ma perchè molti invece usano questa forma?

byte miobyte = 129;
byte MSB = (miobyte >> 7) & 1;
Forse perché questo è un modo generico di ottenere il valore del bit n+1 all'interno del byte (nel tuo esempio n=7). Inoltre dovrebbe funzionare anche per tipi di variabili signed e con più byte, tipo int (scusa se uso il condizionale ma vado a memoria).
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 28-04-2020, 18:50   #7
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
Quote:
Originariamente inviato da wingman87 Guarda i messaggi
Invece di passare il valore della variabile, puoi passare l'indirizzo della variabile
Esempio:

Codice:
main()
{
	char *pippo;
	//... pippo viene inizializzato in qualche modo
	pluto(&pippo);
	//giunti qui pippo è stato incrementato di 1
}

int pluto(char **pippo)
{
	(*pippo)++;
}
Ho messo le parentesi in (*pippo)++; perché non ricordo la precedenza degli operatori, nel dubbio con le parentesi non ci sono equivoci.

Forse perché questo è un modo generico di ottenere il valore del bit n+1 all'interno del byte (nel tuo esempio n=7). Inoltre dovrebbe funzionare anche per tipi di variabili signed e con più byte, tipo int (scusa se uso il condizionale ma vado a memoria).

si, è proprio come nel tuo esempio.
Così posso evitare variabili globali che potrebbero creare qualce problema di difficile soluzione.
Non aveva mai usato funzioni col doppio asterisco, c'è smpre una prima volta; grazie 1000
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 29-04-2020, 08:36   #8
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
vi risulta una cosa del genere?

Codice:
char *a;
a = (char *) malloc(sizeof(char) * 10);
a+=5;
free(a); // errore, non viene liberata tutta la memoria
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 30-04-2020, 03:28   #9
frncr
Senior Member
 
Iscritto dal: May 2009
Messaggi: 840
Il parametro passato a free() deve corrispondere a un indirizzo precedentemente restituito da una malloc(), altrimenti il comportamento della funzione è indefinito, perciò quel codice è effettivamente errato.
frncr è offline   Rispondi citando il messaggio o parte di esso
Old 30-04-2020, 10:36   #10
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
grazie per la conferma
misterx è offline   Rispondi citando il messaggio o parte di esso
Old 01-05-2020, 12:51   #11
Volutomitra
Member
 
Iscritto dal: Feb 2006
Messaggi: 134
Quote:
Originariamente inviato da misterx Guarda i messaggi
approfitto di questo mia 3d per chiedervi:

se voglio sapere se l'MSB è settato, mi basta nel caso di un byte verificare che il suo valore sia < 128.
Tutti quelli maggiori o uguali hanno l'MSB settato a 1, ma perchè molti invece usano questa forma?

byte miobyte = 129;
byte MSB = (miobyte >> 7) & 1;
Io farei, e di solito faccio, così:

(miobyte & 0x80)

Ma ragiono per microcontrollori, dove sprecare operazioni inutili è un delitto
Volutomitra è offline   Rispondi citando il messaggio o parte di esso
Old 03-05-2020, 09:09   #12
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 12580
Quote:
Originariamente inviato da Volutomitra Guarda i messaggi
Io farei, e di solito faccio, così:

(miobyte & 0x80)

Ma ragiono per microcontrollori, dove sprecare operazioni inutili è un delitto
Sono sempre per la soluzione che è più facile da leggere, come la tua .

In ogni caso lì dove entrano in gioco costanti, come nel caso accennato da misterx, è molto probabile che il compilatore ottimizzi già da se quelle operazioni, se le ottimizzazioni sono abilitate (come dovrebbe sempre essere ).

Bisognerebbe guardare l'assembly

Una precisazione però, bisogna fare attenzione al tipo di dato, il tipo "byte" in C non esiste, parliamo di char o unsigned char. Nel caso di numeri con segno, i bit più significativi possono essere 1 nel caso di numeri negativi in rappresentazione a complemento a 2.

In generale per memorizzare i flag infatti è consigliabile usare numeri senza segno.

Ultima modifica di WarDuck : 03-05-2020 alle 09:16. Motivo: precisazioni su complemento a 2
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 04-05-2020, 14:28   #13
Volutomitra
Member
 
Iscritto dal: Feb 2006
Messaggi: 134
Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Sono sempre per la soluzione che è più facile da leggere, come la tua .

In ogni caso lì dove entrano in gioco costanti, come nel caso accennato da misterx, è molto probabile che il compilatore ottimizzi già da se quelle operazioni, se le ottimizzazioni sono abilitate (come dovrebbe sempre essere ).

Bisognerebbe guardare l'assembly
Siccome sono un rompiballe sono andato a vedere

Codice:
unsigned char test1(unsigned char value) {
    return (value & 0x80);
}

unsigned char test2(unsigned char value) {
    return ((value >> 7) & 1);
}
compilando con gcc x86-64 9.3, diventa:

Codice:
test1:
        push    rbp
        mov     rbp, rsp
        mov     eax, edi
        mov     BYTE PTR [rbp-4], al
        movzx   eax, BYTE PTR [rbp-4]
        and     eax, -128
        pop     rbp
        ret
test2:
        push    rbp
        mov     rbp, rsp
        mov     eax, edi
        mov     BYTE PTR [rbp-4], al
        movzx   eax, BYTE PTR [rbp-4]
        shr     al, 7
        pop     rbp
        ret
Ho evidenziato le istruzioni corrispondenti ai rispettivi return. Il verdetto è che WarDuck ha ragione, il compilatore ottimizza.

Resta il fatto che ovviamente anche per me la prima versione è più leggibile

Quote:
Originariamente inviato da WarDuck Guarda i messaggi
Una precisazione però, bisogna fare attenzione al tipo di dato, il tipo "byte" in C non esiste, parliamo di char o unsigned char. Nel caso di numeri con segno, i bit più significativi possono essere 1 nel caso di numeri negativi in rappresentazione a complemento a 2.

In generale per memorizzare i flag infatti è consigliabile usare numeri senza segno.
In questo caso avevo ovviamente dato per scontato che il tipo byte fosse unsigned char...
Volutomitra è offline   Rispondi citando il messaggio o parte di esso
Old 05-05-2020, 19:16   #14
WarDuck
Senior Member
 
L'Avatar di WarDuck
 
Iscritto dal: May 2001
Messaggi: 12580
Quote:
Originariamente inviato da Volutomitra Guarda i messaggi
Siccome sono un rompiballe sono andato a vedere

Codice:
unsigned char test1(unsigned char value) {
    return (value & 0x80);
}

unsigned char test2(unsigned char value) {
    return ((value >> 7) & 1);
}
compilando con gcc x86-64 9.3, diventa:

Codice:
test1:
        push    rbp
        mov     rbp, rsp
        mov     eax, edi
        mov     BYTE PTR [rbp-4], al
        movzx   eax, BYTE PTR [rbp-4]
        and     eax, -128
        pop     rbp
        ret
test2:
        push    rbp
        mov     rbp, rsp
        mov     eax, edi
        mov     BYTE PTR [rbp-4], al
        movzx   eax, BYTE PTR [rbp-4]
        shr     al, 7
        pop     rbp
        ret
Ho evidenziato le istruzioni corrispondenti ai rispettivi return. Il verdetto è che WarDuck ha ragione, il compilatore ottimizza.

Resta il fatto che ovviamente anche per me la prima versione è più leggibile
C'è da dire che i due codici non sono perfettamente equivalenti, la prima funzione ritorna 0 oppure 0x80, mentre la seconda 0 oppure 1.

Se uno vuole sapere solo se il bit è settato (quindi è diverso da 0) allora va bene il primo metodo.

Tuttavia bisogna stare attenti perché se si fa il confronto chiedendosi se quel test è uguale a 1 ad esempio, chiaramente si sbaglia.

La cosa interessante è che usando il trucco di negare doppiamente il valore nella prima funzione (portando i valori tra 0 e 1):

Codice:
unsigned char test1(unsigned char value)
{
    return !!(value & 0x80u);
}                                                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                             
unsigned char test2(unsigned char value)
{
    return ((value >> 7u) & 1u);
}
Si ottiene lo stesso assembly (GCC 9.2.x):
Codice:
0000000000000000 <test1>:
   0:	89 f8                	mov    %edi,%eax
   2:	c0 e8 07             	shr    $0x7,%al
   5:	c3                   	retq   
   6:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
   d:	00 00 00 

0000000000000010 <test2>:
  10:	89 f8                	mov    %edi,%eax
  12:	c0 e8 07             	shr    $0x7,%al
  15:	c3                   	retq
È interessante anche notare che l'AND 1 viene eliminato dalla seconda funzione. Questo succede perché entrambi i tipi, del valore e di ritorno sono "unsigned char" e si fa uno shift di 7 quindi il compilatore sà per certo che nell'output tutti i bit eccetto il primo sono 0, rendendo non necessario l'AND.

In tutti gli altri casi, l'AND invece va fatto altrimenti il codice non sarebbe corretto . Se usate unsigned int ad esempio, l'AND compare:

Codice:
0000000000000010 <test2>:
  10:	89 f8                	mov    %edi,%eax
  12:	c1 e8 07             	shr    $0x7,%eax
  15:	83 e0 01             	and    $0x1,%eax
  18:	c3                   	retq
Le bellezze di GCC
WarDuck è offline   Rispondi citando il messaggio o parte di esso
Old 05-05-2020, 19:27   #15
misterx
Senior Member
 
Iscritto dal: Apr 2001
Città: Milano
Messaggi: 3594
siete andati avanti, grandi

Io sto usando quella verifica in un

Codice:
while(variabile < 0x80)
{ ...... }
ed ho notato in definitiva svolge lo stesso compito

Ultima modifica di misterx : 05-05-2020 alle 19:32.
misterx è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Lenovo ThinkVision 3D 27, la steroscopia senza occhialini Lenovo ThinkVision 3D 27, la steroscopia senza o...
La Formula E può correre su un tracciato vero? Reportage da Misano con Jaguar TCS Racing La Formula E può correre su un tracciato ...
Lenovo LEGION e LOQ: due notebook diversi, stessa anima gaming Lenovo LEGION e LOQ: due notebook diversi, stess...
Nothing Ear e Ear (a): gli auricolari per tutti i gusti! La ''doppia'' recensione Nothing Ear e Ear (a): gli auricolari per tutti ...
Sony FE 16-25mm F2.8 G: meno zoom, più luce Sony FE 16-25mm F2.8 G: meno zoom, più lu...
SSD 1080 PRO non è quello che pen...
Ring Intercom ed Echo Pop: sconto imperd...
ASML, intesa con il governo olandese: pi...
Portatile Low cost potentissimo: AMD Ryz...
I nuovi coupon nascosti di Amazon: ecco ...
Torna il super tablet da 109€ con displa...
Continuano le super offerte su Google Pi...
Meta copia Microsoft con Windows: il sis...
Blackmagic Design: arriva il nuovo softw...
La sonda spaziale NASA Voyager 1 ricomin...
Blackmagic PYXIS 6K per riprendere filma...
Sapphire Nitro+ B650I Wi-Fi: un’ottima s...
E4 Computer Engineering potenzierà...
Blackmagic URSA Cine 12K: la videocamera...
Ecco i TV TCL in esclusiva per Amazon: p...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 08:21.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Served by www1v