Pagina 2 di 2 primaprima 1 2
Visualizzazione dei risultati da 11 a 17 su 17

Hybrid View

  1. #1
    Utente di HTML.it L'avatar di torn24
    Registrato dal
    Aug 2008
    Messaggi
    551

    Ciao

    Il problema di sizeof() su variabile extern, è una questione interessante, e anche io vorrei dei chiarimenti.

    Ma nello specifico usi un array statico, e quindi non è indispensabile l'uso di sizeof(), in quanto conosci già di quanti elementi è costituito l'array, e la traccia dell'esercizio non fa' nessun riferimento al suo uso.

    quindi il tuo esercizio si potrebbe risolvere semplicemente.


    Main:
    codice:
    #include <stdio.h>
    
    
    
    
    unsigned dati_comuni[]={2,5,7,1,65,34,8,10};
    int main(void)
    {
       int i;
       ordina_dati();
    
    
    
    
        for (i=0; i<8; i++) {
               printf("elemento %d vale %d\n",i,dati_comuni[i]);
        }
        getchar();
        return 0;
    }

    Funzioni.c :
    codice:
    #include <stdio.h>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    void ordina_dati(void){
        int i,j,min,temp;
    
    
        extern unsigned int dati_comuni[];
    
    
    
    
        
    
    
        for(i=0; i<8; i++)
        {
            min = i;
    
    
            for(j=i+1; j<8; j++)
                if(dati_comuni[j] < dati_comuni[min])
                    min = j;
    
    
            temp=dati_comuni[min];
            dati_comuni[min]=dati_comuni[i];
            dati_comuni[i]=temp;
        }
    
    
    }
    Tecnologia

  2. #2
    1. Sarebbe buona regola dare un'indentata decente al codice ed eliminare tutti gli spazi, prima di postare.
    2. Come nel file funzioni.c è ignoto l'array, anche nel file main.c è ignota la funzione di ordinamento dell'array. Va specificata anch'essa con extern.
    3. Se un tipo di dato è unsigned, va stampato con la direttiva di conversione %u (e non %d che viene usata per gli interi con segno).
    4. Come ho già ribadito nel mio primo post, la sizeof viene "eseguita" a compile time, quindi, quando un array statico si trova in un file differente, il compilatore non può conoscerne (a priori) la dimensione.
    5. Se si vuole comunque utilizzare la sizeof, per ottenere il numero degli elementi presenti in un array statico (procedimento di utilità quasi nulla, nel mondo reale della programmazione), va specificato, sulla extern, il numero di elementi dell'array.
    6. La sizeof restituisce sempre il numero di byte quindi, per conoscere la dimensione di un qualsiasi array, basta dividere il numero di byte dell'array, per il numero di byte del singolo elemento.


    Per farla breve, il codice corretto (e correttamente indentato) è il seguente.

    file: main.c
    codice:
    #include <stdio.h>
    
    
    unsigned dati_comuni[8] = {10, 5, 7, 1, 65, 34, 8, 10};
    extern void ordina_dati(void);
    
    
    int main(void) {
        int i;
        
        ordina_dati();
    
    
        for(i = 0; i < sizeof(dati_comuni)/sizeof(unsigned); i++) {
            printf("Elemento %d vale %u\n", i, dati_comuni[i]);
        }
    
    
        getchar();
        return 0;
    }

    file: funzioni.c
    codice:
    void ordina_dati(void) {
        unsigned i, j, temp;
    
    
        extern unsigned dati_comuni[8];
    
    
        for(i = 0; i < sizeof(dati_comuni)/sizeof(unsigned); i++) {
            for (j = i + 1; j < sizeof(dati_comuni)/sizeof(unsigned); j++) {
                if(dati_comuni[i] > dati_comuni[j]) {
                    temp = dati_comuni[i];
                    dati_comuni[i] = dati_comuni[j];
                    dati_comuni[j] = temp;
                }
            }
        }
    }

    Su gcc questi due file vanno compilati nel seguente modo:
    codice:
    gcc funzioni.c main.c -o nome_programma

    Ma nello specifico usi un array statico, e quindi non è indispensabile l'uso di sizeof(), in quanto conosci già di quanti elementi è costituito l'array, e la traccia dell'esercizio non fa' nessun riferimento al suo uso.
    Il problema non è tanto l'utilizzo della sizeof, ma l'utilizzo dell'array statico. Se non ricordo male, su alcuni compilatori, non è possibile modificarne gli elementi a runtime, perché gli oggetti in esso contenuti vengono dichiarati come costanti.
    Al di là di questo, gli unici utilizzi che posso immaginare per un array globale statico sono due:
    • Salvataggio di risorse da utilizzare a runtime (ad esempio un'immagine in formato xpm),
    • Impostazioni e parametri di configurazione.

    L'ultima voce è talvolta considerata un male, perché si irrigidisce la struttura del programma (hard coding).
    In ogni caso, quando si è costretti ad utilizzare un array statico, ci si deve comportare in due modi:
    • Si inserisce nel codice una variabile/costante/macro che indica la grandezza dell'array
    • Si utilizza sizeof

    per non dover andare in giro per il codice a modificare i valori che si riferiscono alla dimensione dell'array.

    Spero di essere stato chiaro
    Ultima modifica di Xaratroom; 05-09-2014 a 18:05 Motivo: Aggiunta delucidazione finale
    Experience is what you get when you don’t get what you want

  3. #3
    Utente di HTML.it L'avatar di torn24
    Registrato dal
    Aug 2008
    Messaggi
    551
    I chiarimenti sono ben accetti.

    Ma tengo a precisare.

    1) Io curo l'indentazione quando il codice sono io a scriverlo, e mi "rompe" correggere l'indentazione di codice scritto da altri e da me solo modificato.

    2) Per una funzione che non accetta parametri, e debba lavorare su una variabile dichiarata esternamente ad essa , questa deve essere per forza globlale, oggi con la programmazione ad oggetti, è difficile pensare che sia utile una variabile globale, ma evidentemente i creatori del linguaggi C non la pensavano in quel modo, penso sia il solo modo di risolvere questo esercizio mantenendo il prototipo indicato, quindi non trovo utile discutere se sia un bene o no.


    Comunque ringrazio per i chiarimenti, sempre utili e bene accetti, se questi rispettosi del prossimo
    Ultima modifica di torn24; 06-09-2014 a 06:30
    Tecnologia

  4. #4
    Quote Originariamente inviata da torn24 Visualizza il messaggio
    1) Io curo l'indentazione quando il codice sono io a scriverlo, e mi "rompe" correggere l'indentazione di codice scritto da altri e da me solo modificato.
    Ma infatti non ce l'avevo con te. Se l'autore del thread avesse indentato correttamente il codice, si sarebbe anche accorto dell'errore nell'algoritmo di ordinamento (che non ordina un bel niente):
    codice:
    for(i=0; i<8; i++){
        min = i;
        for(j=i+1; j<8; j++)
            if(dati_comuni[j] < dati_comuni[min])
                min = j;
        temp=dati_comuni[min];
        dati_comuni[min]=dati_comuni[i];
        dati_comuni[i]=temp;
    }


    Quote Originariamente inviata da torn24 Visualizza il messaggio
    2) Per una funzione che non accetta parametri, e debba lavorare su una variabile dichiarata esternamente ad essa , questa deve essere per forza globlale, oggi con la programmazione ad oggetti, è difficile pensare che sia utile una variabile globale, ma evidentemente i creatori del linguaggi C non la pensavano in quel modo, penso sia il solo modo di risolvere questo esercizio mantenendo il prototipo indicato, quindi non trovo utile discutere se sia un bene o no.
    Dipende un po' da quello che si deve andare a fare. Non vorrei andare OT ma puoi simulare una programmazione a oggetti anche in C. Per farlo utilizzi le strutture e (talvolta) dei file che lavorano su variabili globali. In questo contesto, l'utilizzo di variabili globali (e di funzioni prive di parametri) non è da considerare un male, perché simula il funzionamento di una classe. Per quanto riguarda la extern, io personalmente l'ho solo utilizzata in applicazioni ibride C/C++ e Assembly (scrivi la tua funzione in assembly e poi la unisci al tuo codice in fase di linking). Per tutti gli altri scenari ho sempre utilizzato gli header file.


    Quote Originariamente inviata da torn24 Visualizza il messaggio
    Comunque ringrazio per i chiarimenti, sempre utili e bene accetti, se questi rispettosi del prossimo
    Non volevo sembrare in nessun modo offensivo, ma solo fornire un resoconto degli errori.
    Experience is what you get when you don’t get what you want

  5. #5
    Quote Originariamente inviata da Xaratroom Visualizza il messaggio
    Dipende un po' da quello che si deve andare a fare. Non vorrei andare OT ma puoi simulare una programmazione a oggetti anche in C. Per farlo utilizzi le strutture e (talvolta) dei file che lavorano su variabili globali. In questo contesto, l'utilizzo di variabili globali (e di funzioni prive di parametri) non è da considerare un male, perché simula il funzionamento di una classe.
    Vale la pena di spendere qualche parola sull'argomento, anche se parzialmente OT.
    Il problema è legato ai numerosi scenari di utilizzo del linguaggio C nei vari "universi paralleli". In linea generale, i migliori testi di engineering e le guide di stile generaliste sono concordi nel deprecare qualunque uso delle variabili globali, poiché:

    1) Non vi è alcun controllo, in linguaggi come il C, sull'accesso in scrittura a tali variabili da parte di funzioni tra loro indipendenti e scorrelate, con tutte le conseguenti difficoltà di debug, potenzialità di conflitto ed errore;

    2) L'uso estensivo di tale tecnica in qualche misura confligge con il principio di information hiding di Parnas, che è poi diventato uno dei pilastri portanti della OOP ma che rimane un principio guida per la modularizzazione e decomposizione funzionale del software, sostanzialmente indipendente dal paradigma utilizzato.

    Questo è quanto uno studente ben preparato dovrebbe ritenere dopo un buon corso di software engineering o corso avanzato sul linguaggio C. Tuttavia, vi è molto altro da chiarire in merito. Se gli scenari di uso applicativo "object-oriented" dei linguaggi di più basso livello rappresentano una nicchia decisamente minoritaria anche rispetto all'emulazione di altre tecniche altrettanto di nicchia (es. ADT), occorre invece focalizzare l'attenzione sulla colossale singolarità dei miliardi di linee di codice prodotti per piattaforme non maistream. Nella maggior parte dei cross-compiler C per target baseline e midrange, tutti i passaggi di parametri avvengono tramite variabili globali, sebbene all'insaputa del programmatore poco avveduto che formalmente scrive il suo bravo programmino come ha appreso a scuola. Questo perché il concetto stesso di "stack" è del tutto irrilevante sulla schiacciante maggioranza delle piattaforme Harvard, e i concetti correlati di parameter stack e call stack vengono gestiti in hardware (il primo quasi mai, ad onor del vero) in modo non modificabile, o emulati laddove necessario, con ampio uso di salti incondizionati e variabili condivise, talora allocate in aree di memoria dedicate, ad accesso privilegiato e quindi in ultima analisi con prestazioni assai maggiori.

    In tali ambienti, anche trascurando in parte ciò che avviene under the hood, l'uso esplicito di variabili globali a livello di programma (che per inciso ha un innegabile vantaggio prestazionale anche sulle piattaforme mainstream) è una prassi consolidata e asseverata, riconosciuta valida a livello di engineering globale. Questo è il più importante e valido esempio di inversione del paradigma nel passaggio dalla programmazione dei sistemi mainstream a quella dei sistemi di elaborazione dedicati.

    Viceversa, nella programmazione mainstream del real world l'uso di variabili con scope globale deve essere sempre esplicitamente giustificato a livello di progetto, generalmente col supporto di motivazioni prestazionali e/o di abbattimento della complessità ciclomatica del codice, ciò che - al di là di esigenze didattiche più o meno estemporanee - appunto pertiene a casistiche come l'emulazione di paradigmi non nativi del C o la stesura di software fortemente orientati alle prestazioni.
    • Un plauso a Grisha Perelman, raro esempio di genuino anticonformismo umano e scientifico.

  6. #6
    Già che ci siamo (OT) vorrei un attimino integrare quanto detto in precedenza.
    In primis ho citato l'hard conding, in riferimento all'utilizzo di parametri di configurazione, direttamente codificati nel programma.
    Questo l'ho capito appieno solo dopo aver perso 2 giorni per ricompilare un vlc su arm perché, il pacchetto presente sui repo, non aveva l'accelerazione hardware abilitata.


    Per quanto riguarda l'utilizzo delle variabili a scope globale (siano esse delle semplici variabili globali, o delle orribili classi statiche, con attributi pubblici, poco importa), sono sostanzialmente d'accordo con quanto già scritto da M.A.W. sullo scenario embedded.
    Vorrei però aggiungere che, sulle piattaforme mainstream, il problema prestazionale è generalmente scavalcato dalla continua "crescita" dell'hardware (e pone le sue radici su mercati che potremmo definire, anche in questo caso, di nicchia). Nonostante quindi, il problema prestazionale, sia da tempo considerato di secondo piano, rispetto a problemi come la manutenibilità e la scalabilità, è altresì vero che, l'utilizzo di variabili a scope globale, è una pratica più che diffusa nella programmazione di tutti i giorni (basti pensare alla stragrande maggioranza dei CMS, framework di sviluppo, etc)... perchè?
    In un mondo frenetico come quello dell'IT, l'utilizzo di variabili globali (e qui potremmo anche generalizzare, ma poi andremmo ancora più OT) può rappresentare (talvolta) una notevole scorciatoia in fase di sviluppo.
    Se da un lato questo rappresenta un malus (per i motivi già citati da M.A.W.) è anche vero che l'introduzione di debito tecnico, in fase di sviluppo, non è una pratica mal vista in ingegneria del software. Soprattutto se si parte dal presupposto (valido più nei grossi progetti software che nei piccoli) che non esistono soluzioni perfette (ma solo soluzioni ottimali) perché, in fase di sviluppo, vanno considerate innumerevoli variabili: tempo, risorse economiche, risorse tecniche, limiti dei sistemi hardware, etc.
    Tutto sta quindi nel riuscire a definire, in fase di design o di stesura del codice (queste due spesso non sono disgiunte), se una pratica può rientrare nel debito tecnico (e potrà essere eventualmente migliorata in un secondo momento) o se va evitata.
    Experience is what you get when you don’t get what you want

  7. #7
    Il problema è in realtà molto più profondo di quanto sia possibile trattare in un breve OT, e non attiene unicamente un dettaglio - sia pure rilevante - come l'uso di variabili con scope globale.

    Di fatto, come da anni mi trovo a spiegare in aula e su vari forum, esistono oggi almeno due grandi filoni distinti e contrapposti del software engineering: l'uno tradizionale, radicato nei settori più critici di applicazione del software, come il militare, l'aerospaziale, il petrolifero e l'energetica, il biomedicale, l'automotive, i trasporti... settori normati in modo severo da rigorose normative internazionali, nei quali l'errore è semplicemente inammisibile a causa dei costi connessi (economici e perfino in termini di salute e vite umane ed animali!). Una scuola di engineering della quale anche il sottoscritto è a buon diritto considerato un rappresentante, che impone costi non ricorrenti notevoli ma ragionevoli a fronte dell'eventuale danno futuro derivante da errori, con relativo dimensionamento delle risorse tecnico-economiche all'altezza della situazione.

    L'altro filone invece, di assai più recente concezione, è di fatto legato a scuole di pensiero come "agile" ed "extreme programming" e si connota come totalmente radicato nel mainstream, nel web, e in altri mercati analoghi. L'approccio utilizzato cerca di fare fronte ai problemi endemici del mainstream con tecniche adattative, minimizzazione delle risorse e una generale mentalità "lean" che lascia ampio scetticismo in molti teorici e practitioner di formazione più tradizionale.

    Tali filoni, infatti, da tempo si fronteggiano aspramente (già una decina d'anni fa iniziavano a comparire articoli fortemente critici di mostri sacri come il già citato David Parnas e anche di nostrani docenti molto rispettati, come Ghezzi e Monga) senza riuscire a trovare una sintesi, poiché le premesse divergono ormai fortemente e comunque appare sempre più chiaro che - pur a fronte di problemi notevoli - il mainstream non è disposto a farsi carico dei costi e dei tempi richiesti dai metodi overkill che usiamo quotidianamente nei settori più critici: progettazione integrata hardware/software (codesign) ben separata dalle fasi implementative, uso sistematico di metodi e linguaggi formali (CASL, Z, CSP, VDM, logiche temporali, BDD...) per specifica e verifica, ricorso obbligatorio e documentato a strumenti per l'analisi statica e dinamica del codice (vedi Polyspace e i vari Absint, fino ai più elementari checker MISRA o SPLint), ricorso a RTOS e runtime certificati e/o certificazione full code coverage di terze parti dell'intero progetto, e in breve tutto l'arsenale di metodi e procedure adottate e sviluppate in seno al software engineering "tradizionale" (quello delle edizioni classiche, ante-web dei vari Pressman, Sommerville, eccetera...) dalla fine degli anni Ottanta.

    Detto questo, a beneficio degli studenti che ci leggono e cercano di decidere "cosa fare da grandi", resto ovviamente a disposizione per qualsivoglia chiarimento ma terminerei qui l'OT.
    Ultima modifica di M.A.W. 1968; 07-09-2014 a 15:31
    • Un plauso a Grisha Perelman, raro esempio di genuino anticonformismo umano e scientifico.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.