Newsgroup: it.comp.lang.c
Titolo: Register?

Ho trovato questa parola chiave in alcuni programmi C per il DJGPP, e
mi chiedevo a cosa servisse.
register int prova;
Come unica ipotesi ho pensato ad un'indicazione per il compilatore ad
usare (se possibile) un registro della CPU per mantenere in memoria la
variabile interessata.
Penso bene?
Se si, quanti di questi 'suggerimenti' possono essere presi in
considerazione, visto che i registri disponibili sono limitati? (A me
interessa il caso della famiglia Intel 386).
Un saluto e un grazie a tutti.
Ciao, Piero.

 interessa il caso della famiglia Intel 386).
Il 386 ha 4 registri general-purpose a 32 bit, 4 a 16 bit, e 8 a 8 bit.
(ovviamente sovrapposti, per cui non puoi sommarli per ottenere 16 registri)
--
Alessandro Monti

 limitati? (A me interessa il caso della famiglia Intel 386).
  Dipende dalla situazione contingente e dalle strategie del
compilatore. Le /info-page/ della GNU si dilungano parecchio su questi
argomenti, potresti darci un'occhiata.
	Alla prossima,
		Marco

 
Si. Lo standard mette a disposizione questa classe di memorizzazione
proprio per permettere la gestione ottimale delle tecnologie.
Attenzione: di una variabile memorizzata come register non si deve
richiedere il puntatore con &var perche' non e' garantito che sia
ne' contigua, ne che sia in una posizione fissa, ne che sia
indirizzabile.
I parametri di funzione hanno classe di memorizzazione register comunque
quindi:
in funzione( int parametro)
{
  int * pint;
  pint = & parametro; /* SBAGLIATO!! */
}
ciao.

 
Purtroppo non penso ci sia modo di sapere se una variabile dichiarata
register e' stata effettivamente memorizzata in un registro o meno, in
quanto quando e' possibile viene fatto, quando non lo e' la varaibile
viene posta in memoria ad insaputa del programmatore.
Tiene presente che questo pone delle limitazioni in ogni caso (i.e. sia
che sia effettivamente messa su un registro o che sia messa in memoria):
ad esempio una variabile di tipo register non puo' essere referenziata
con l'operatore '&'
-- 
Zack
Stefano Zacchiroli
zacc...@cs.unibo.it
za...@comune.budrio.bo.it
ICQ# 33538863
"Never understimate the dark side"

 }
Cavolo! Questa non la sapevo! Grazie dell'informazione. Per scrupolo,
qualcun'altro conferma questa affermazione? Il DJGPP non dà alcuna
segnalazione né di errore né di warning. Ma d'altronde non lo dà neanche
nel caso di una variabile esplicitamente dichiarata register...
EMG

 nel caso di una variabile esplicitamente dichiarata register...
A me risultava che se chiedevi l'indirizzo, non effettuava nessuna
ottimizzazione, neanche se la dichiari register, in quanto, appunto, non è
ottimizzabile.
Quindi non confermo, ma potrei sbagliarmi.
In particolare non so se lo standard dice qualcosa o se dipende
dall'implementazione.
--
Alessandro Monti


Questa proprio non l'ho mai sentita; non so cosa dice lo standard, ma 
i parametri delle funzioni vengono passati nello stack, ed e' perfettamente
legale prenderne l'indirizzo, anche se non riesco ad immaginare quale utilita' 
ci sia nel fare una cosa del genere.

 nel caso di una variabile esplicitamente dichiarata register...
L'associazione il tra parametro di funzione e la classe di memorizzazione
"register" dipende dal OS e dal compilatore. Comunque, credo che quasi tutti i
compilatori moderni evitino al programmatore la fatica di ottimizzare la
memoria allocata con la classe di memoria "register".
Raffaele.


Non e` necessariamente vero che i parametri sono passati nello stack.
Per la verita` il problema non me lo ero mai posto, pero`  ad esempio
nell'architettura Alpha della Digital ci 6 registri "interi" piu` altrettanti
registri "float" riservati al passaggio dei parametri, nel senso che i primi
sei parametri "interi" ("float")  vengono passati nei registri interi ("float")
mentre dal settimo in poi vengono inseriti nello stack, per cui potrebbe
essere vero che prendere l'indirizzo di un parametro e` un errore, anche
se non so cosa dice lo standard al riguardo.
Marco Guidi.
 

 wrote:
[ snip ]
EMG>segnalazione né di errore né di warning. Ma d'altronde non lo dà neanche
EMG>nel caso di una variabile esplicitamente dichiarata register...
Strano.
[bigfok@fokhouse reg]$ cat >test.c
int func(void)
{
        register int pippo;
        int *p;
        p = &pippo;
        return 0;
}
[bigfok@fokhouse reg]$ gcc -Wall -ansi -pedantic -c test.c
test.c: In function `func':
test.c:6: warning: address of register variable `pippo' requested
[bigfok@fokhouse reg]$ gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/egcs-2.91.66/specs
gcc version egcs-2.91.66 19990314/Linux (egcs-1.1.2 release)
Ciao ciao,
Andrea
-- 
"...Unix, MS-DOS, and Windows NT (also known as the Good, the Bad, and 
 the Ugly)."
(by Matt Welsh)

 
!???!?!?!?!?!? Vuoi dire che non si puo' fare una cosa tipo :
in funzione( int parametro)
 {
   ....
   funzione2(&parametro);
   ....
 }
void funzione2(int *pippo);
Ma sei sicuro? Spero di no..... ;-)
-- 
 Ciao, Luca.
 Reply to 
luca....@tiscalinet.it
 UIN : 43385135

 
Sono sicuro di averlo letto su un testo che non ricordo, che trattava
lo standard ANSI e ne ho anche capito il senso. Il fatto che su molti
compilatori funzioni significa solo che i progettisti hanno fatto certe
scelte tecnologiche, ma un compilatore che tratta realmente i parametri
come register e segnala errori in caso di richiesta di indirizzo, si
possono comunque considerare conformi allo standard. Io nei dubbi evito,
se vale la pena porsi il problema, sintassi non standard. A volte per
applicazioni non vale la pena, ma nel progetto di librerie do' molta
importanza alla portabilita' tra piattaforme e tra compilatori della
stessa
piattaforma. Sia ben chiaro che non mi e' mai servito ricavare l'
indirizzo
di un parametro, comunque ho sperimentato che il gcc sotto Linux lo
permette
anche con
cc -Wall -ansi -pedantic
Comunque se e' cosi' importante, forse e' meglio se ti documenti da
altre
fonti. Non saprei reperire il mio testo.
ciao.

 
[...]
Ok, grazie per il chiarimento, pero' adesso mi viene un dubbio: se
volessi fare quello che ho indicato nell'esempio, come risolverei il
problema? Dovrei fare per forza :
 
  in funzione( int parametro)
  {
    ....
    parametro = funzione2(parametro);
    ....
  }
  int funzione2(int pippo)
  {
   ....
   return pippo;
  }
giusto? Non e' poi cosi' grave...


you wrote :
#I parametri di funzione hanno classe di memorizzazione register comunque
#quindi:
Dove l'hai letto ? ...
...sul manuale di H. Shildt ? ;) 
int funzione( int p )
{
    int * pint ;
    register int a ;
    pint = &a ;  /* <--- segnalazione di warning (corretta) */
}
int funzione( int p )
{
    int * pint ;
    pint = &p ;  /* <--- compilazione corretta */
}
Le variabili locali risiedono nello stack ed essendo quest'ultimo
parte integrante della memoria e' possibile calcolare l'address-of di
qualsiasi oggetto in esso contenuto.
--------------------------------------------------------
* Andrea Laforgia        (
andrea_...@bigfoot.com
) *
--------------------------------------------------------

 ...sul manuale di H. Shildt ? ;)
Beh, io non avevo letto lo Schildt, ma mi risulta che il metodo "standard"
di passaggio dei parametri in C sia con i registri, se possibile. Questo č
uno dei motivi per cui in C passare array e strutture viene tradotto con
l'indirizzo delle strutture.
Idem per i valori di ritorno, e per questo motivo č possibile ritornare un
solo valore o un puntatore.
Puņ darsi che non sia standard ma K&R. Oppure ho letto troppi manuali del
compilatore invece che lo standard.
--
Alessandro Monti

 problema? Dovrei fare per forza :
Non so se lo faccia, ma un compilatore potrebbe accorgersene e copiare il
valore sullo stack, se necessario.
Comunque non ha alcun senso chiedere l'indirizzo di un parametro, comunque
sia passato.
--
Alessandro Monti

 l'indirizzo delle strutture.
Se non hai letto lo Schildt devi aver letto qualcosa di molto simile.
:-) In C/C++ le strutture possono essere passate e restituite sia per
valore che per riferimento, come ti dimostra questo programmino:
#include <stdio.h>
typedef struct
{
    int a;
    int b;
    int c;
    int d;
} S;
void pippo( S s )
{
    s.b = 321;
    printf( "In pippo: %d\n", s.b );
}
int main()
{
    S s;
    s.b = 123;
    printf( "Prima di pippo: %d\n", s.b );
    pippo( s );
    printf( "Dopo pippo: %d\n", s.b );
    return 0;
}
Mi sembra che fosse come dici tu nella prima versione del C K&R.
EMG

 Le variabili locali risiedono nello stack 
A me non risulta che questo sia garantito, specialmente per i parametri
pero` magari mi sbaglio.
Riporto di seguito la traduzione assembler dei due diversi programmi
che seguono (macchina Digital Alpha, compilatore per Digital Unix).
Nel primo caso viene usato lo stack, nel secondo viene fatto tutto con
i registri ($16 e` il registro utilizzato per il passaggio del
1. parametro intero). Questo sembrerebbe indicare che il compilatore e`
sufficentemente "furbo" da tradurre usando lo stack solo quando e` necessario.
Ma questo comportamento e` garantito ?
Marco Guidi
file b.c
int funzione1(int p) {
     int * pint=&p ;
     *pint=7;
     return 0;
}
int main(void) {
    funzione1(4);
    return 0;
}
Traduzione in assembler (cc -S b.c):
        .ugen
        .verstamp       3 11
        .text
        .align  4
        .file   2 "b.c"
        .globl  funzione1
        .loc    2 1
 #    1  int funzione1(int p) {
        .ent    funzione1 2
funzione1:
        .option O1
        ldgp    $gp, 0($27)
        lda     $sp, -64($sp)
        stq     $16, 16($sp)
        .frame  $sp, 64, $26, 48
        .prologue       1
        .loc    2 1
        .loc    2 2
 #    2      int * pint=&p ;
        lda     $1, 16($sp)
        stq     $1, 8($sp)
        .loc    2 3
 #    3      *pint=7;
        ldil    $2, 7
        stl     $2, 0($1) #inserisce 7 sullo stack
        .loc    2 4
 #    4      return 0;
        bis     $31, $31, $0
        .livereg        0xFC7F0002,0x3FC00000
        lda     $sp, 64($sp)
        ret     $31, ($26), 1
        .end    funzione1
        .text
        .align  4
        .file   2 "b.c"
        .globl  main
        .loc    2 7
 #    5 }
 #    6
 #    7 int main(void) {
        .ent    main 2
main:
        .option O1
        ldgp    $gp, 0($27)
        lda     $sp, -16($sp)
        stq     $26, 0($sp)
        .mask   0x04000000, -16
        .frame  $sp, 16, $26, 0
        .prologue       1
        .loc    2 7
        .loc    2 8
 #    8     funzione1(4);
        ldil    $16, 4
        .livereg        0x00018002,0x00000000
        jsr     $26, funzione1
        ldgp    $gp, 0($26)
        .loc    2 9
 #    9     return 0;
        bis     $31, $31, $0
        .livereg        0xFC7F0002,0x3FC00000
        ldq     $26, 0($sp)
        lda     $sp, 16($sp)
        ret     $31, ($26), 1
        .end    main
file c.c
int funzione1( int p ) {
     int * pint ;
     p=7;
     return 0;
}
int main(void) {
    int a;
    funzione1(4);
    return 0;
}
Traduzione in assembler
        .ugen
        .verstamp       3 11
        .text
        .align  4
        .file   2 "c.c"
        .globl  funzione1
        .loc    2 1
 #    1 int funzione1( int p ) {
        .ent    funzione1 2
funzione1:
        .option O1
        ldgp    $gp, 0($27)
        lda     $sp, -16($sp)
        .frame  $sp, 16, $26, 0
        .prologue       1
        addl    $16, 0, $16
        .loc    2 1
        .loc    2 3
 #    2      int * pint ;
 #    3      p=7;
        ldil    $16, 7 # 7 viene caricato nel registro $16 e mai inserito
                       # sullo stack.
        .loc    2 4
 #    4      return 0;
        bis     $31, $31, $0
        .livereg        0xFC7F0002,0x3FC00000
        lda     $sp, 16($sp)
        ret     $31, ($26), 1
        .end    funzione1
        .text
        .align  4
        .file   2 "c.c"
        .globl  main
        .loc    2 7
 #    5 }
 #    6
 #    7 int main(void) {
        .ent    main 2
main:
        .option O1
        ldgp    $gp, 0($27)
        lda     $sp, -32($sp)
        stq     $26, 0($sp)
        .mask   0x04000000, -32
        .frame  $sp, 32, $26, 0
        .prologue       1
        .loc    2 7
        .loc    2 9
 #    8     int a;
 #    9     funzione1(4);
        ldil    $16, 4
        .livereg        0x00018002,0x00000000
        jsr     $26, funzione1
        ldgp    $gp, 0($26)
        .loc    2 10
 #   10     return 0;
        bis     $31, $31, $0
        .livereg        0xFC7F0002,0x3FC00000
        ldq     $26, 0($sp)
        lda     $sp, 32($sp)
        ret     $31, ($26), 1
        .end    main


 Ma questo comportamento e` garantito ?
Sembra che sia cosě, cioč che la maggior parte dei compilatori sia "furba". ^__^
Qualcuno conferma?
Raffaele.

you wrote :
#> Le variabili locali risiedono nello stack 
#
#A me non risulta che questo sia garantito, specialmente per i parametri
#pero` magari mi sbaglio.
In effetti bisognerebbe osservare il problema avendo presente le
diverse piattaforme, e' una questione dipendente dall'implementazione.
E' uso molto comune trattare i parametri di funzione come variabili
residenti nello stack (per lo meno, molti (tutti?) i compilatori per
piattaforme DOS/Windows trattano i parametri in quel modo).
E' strano, comunque, se non altro per ragioni di portabilita', che il
DJGPP non segnali un errore fatale in fase di compilazione, con tutte
le opzioni di warning spinte ai massimi livelli.
Questo mi fa pensare...


you wrote :
#Beh, io non avevo letto lo Schildt, ma mi risulta che il metodo "standard"
#di passaggio dei parametri in C sia con i registri, se possibile.
Non credo esista un metodo "standard" di passaggio dei parametri,
perche' lo standard si mantiene lontano da questi aspetti specifici.
Se invece per "standard" intendi per "default", non credo sia cosi',
perche' altrimenti sarebbero piu' i casi in cui i parametri vengono
passati tramite registri che non tramite stack, e cosi' non e' (almeno
sulle piattaforme DOS/Windows, dove e' vero il contrario).
#Questo è uno dei motivi per cui in C passare array e strutture viene tradotto con
#l'indirizzo delle strutture.
#Idem per i valori di ritorno, e per questo motivo è possibile ritornare un
#solo valore o un puntatore.
Non e' vero, in C si puo' passare una struttura sia per riferimento,
tramite puntatore, che per valore. Lo stesso vale per i valori di
ritorno.
Per quanto riguarda gli array, si e' detto piu' volte che nel caso dei
parametri di funzione essi scelgono la loro "seconda identita'" di
puntatori, semplificando la vita.
Quello che dici era valido per il C pre-ansi (a cui fa riferimento il
K&R I versione) anche se Kernighan e Ritchie non escludono, cosi'
com'e' stato, che miglioramenti sarebbero avvenuti in futuro.
Il seguente codice aderisce allo standard e viene compilato
correttamente :
typedef struct { int a, b ; } STRUCT ;
STRUCT funzione( STRUCT a )
{
  STRUCT s ;
  s.a = 5 ;
  s.b = 4 ;
  return s ;
}
Ammetterai che non e' cosi' frequente trovare dei processori i cui
registri siano in grado di contenere l'intero contenuto di una struct.
In realta', le scelte operate con il C dipendono dalla facilita' di
implementazione di tali meccanismi. Lo stack e' una memoria preziosa e
conviene utilizzare quante meno informazioni per rappresentare gli
stessi dati. 
Il C porta con se' una tradizione di semplicita' da rispettare e per
questo motivo, ad esempio, non implementa ne' il passaggio per
riferimento, ne' le funzioni nidificate (a parere degli autori del
linguaggio troppo complicate da implementare). 


Ecco cosa ho trovato nel Final Committe Draft (JTC1/SC22/WG14 N843 ):
6.9.1 Function definitions
       [#9]  Each  parameter  has  automatic storage duration.  Its |
       identifier is an lvalue, which is in effect declared at  the
       head of the compound statement that constitutes the function |
       body (and therefore cannot be  redeclared  in  the  function |
       body  except  in  an  enclosed  block).   The  layout of the
       storage for parameters is unspecified.
Peccato che non ho trovato nulla sulla legalita'/moralita' di stabilire
un puntatore ad un parametro passato alla funzione. 

        [#9]  Each  parameter  has  automatic storage duration.
Bene. Questo mi sembra ponga fine alla questione, giusto?
EMG

Bene. Questo mi sembra ponga fine alla questione, giusto?
Questo non era mai stato in dubbio; e' sul fatto dell'allocazione in
un registro o nello stack che non dice nulla.

 un registro o nello stack che non dice nulla.
Uff! E' vero. Anche le variabili register hanno classe automatica,
giusto? Allora rimaniamo col dubbio...
EMG

you wrote :
#> Questo non era mai stato in dubbio; e' sul fatto dell'allocazione in
#> un registro o nello stack che non dice nulla.
Certo che lo dice ! c'e' scritto all'ultima riga :
"The layout of the storage for parameters is unspecified."
Lo Standard fa uso di tre espressioni specifiche per designare quegli
aspetti del linguaggio su cui esso non puo' (non vuole) pronunciarsi,
d'altronde ho gia' affermato in un mio messaggio precedente che la
questione e' dipendente dall'implementazione.
In questo caso usa il termine "unspecified" e l'ANSI C Rationale
afferma prima che :
"The terms unspecified behavior, undefined behavior, and
implementation-defined behavior are used to categorize the
result of writing programs whose properties the Standard does not, or
cannot, completely describe.  The goal of adopting this
categorization is to allow a certain variety among implementations
which permits quality of implementation to be an active
force in the marketplace as well as to allow certain popular
extensions, without removing the cachet of conformance to the
Standard."
e poi che :
"Unspecified behavior gives the implementor some latitude in
translating programs.  This latitude does not extend as far as
failing to translate the program."
Questo vuol dire che lo Standard non si pronuncia sul metodo (e mi
sembra anche ovvio che non lo faccia) con cui i parametri vanno
passati alle subroutine, lasciando all'implementatore del compilatore
la scelta nell'uso dello stack o dei registri.
Puo' capitare, difatti, che macchine diverse siano avvantaggiate
dall'uso dell'uno o dell'altro metodo.
Che io sappia, quasi tutti i compilatori per DOS/Windows utilizzano il
metodo del passaggio tramite stack.


Si'. questo discorso mi sembra abbastanza chuaro; forse mi sto perdendo il filo del
discorso. In origine avevo osservato che, pur sembrandomi strano che uno voglia,
in una funzione, usare un puntatore ad uno degli argomenti della funzione, cio' 
dovrebbe comunque essere possibile; non ricordo di avere mai letto da nessuna
parte niente che dica il contrario.

you wrote :

E abbiamo chiarito che il "contrario" dipende dall'implementazione.
Nessuno puo' affermare che sia *certamente* possibile, e' appunto una
questione legata all'implementazione.
