Quali sono le differenze chiave tra lo sviluppo di C di basso livello e lo sviluppo di OOP di livello superiore? [duplicare]

8

Ho usato un linguaggio OOP di alto livello (come C # e / o Java) per parecchio tempo. Conosco modelli come la banda di quattro, in grado di leggere e scrivere codice ragionevolmente bene e sono considerato un anziano dai suoi pari.

Mi sto spostando verso lo sviluppo C a basso livello. Come risultato del mio background, non ho familiarità con molte delle tecnologie e abilità inerenti allo sviluppo / implementazione di livello inferiore.

Quali sono le differenze chiave nella tecnologia e nell'approccio allo sviluppo che devo comprendere per avere successo nello sviluppo C quando provengo da un background OOP di livello superiore?

    
posta Max Yankov 24.09.2015 - 17:33
fonte

4 risposte

6

Dipenderà da quanto "vicino al metallo" avrai bisogno di ottenere. Ma alcune cose comuni che potresti trovare potrebbero non essere familiari a te:

  • A prima vista, la prima cosa a cui devi prestare molta attenzione è gestione delle risorse . C non esegue un garbage collector e non ha finalizzatori automatici (distruttori AKA), quindi allocare un blocco di memoria o aprire un file / socket implica che devi tenere traccia manualmente della durata di quella risorsa e liberarla a qualche punto nel programma. Questo è probabilmente il più grande cambiamento di paradigma, proveniente da Java / C #, ma una volta che ci si abitua, non è un grosso problema. Al giorno d'oggi abbiamo strumenti molto validi che aiutano a tenere traccia delle perdite di risorse, quindi non devi vivere nella paura.

  • C non fornisce una rete di sicurezza . E con questo intendo nessun controllo degli array, nessuna memoria che protegga e pochissima protezione runtime contro errori di programmazione comuni. Potresti aver sentito dire che "C è una pistola grande, ma è molto facile spararti al piede con esso" - e questo è vero, le alte prestazioni di esecuzione richiedono alcuni compromessi e il controllo ondulato dei runtime è uno di quelli. Tutti i meccanismi di sicurezza di cui il tuo programma potrebbe aver bisogno sono implementati da te, la lingua non offre molto out-of-the-box.

  • C è molto leggero , così come la sua libreria standard. Lo standard Lib consiste fondamentalmente in una manciata di funzioni di I / O e funzioni matematiche, questo è tutto. Se ti piacciono i C incorporati, potresti anche non averlo! Nessun bel contenitore e algoritmi generici. Di nuovo, nello spirito della lingua, se la tua applicazione ha bisogno di una funzionalità, la implementa. La lingua e la libreria non fanno supposizioni per te.

  • La digitazione dei dati è molto più allentata in C . Questo è discutibile se buono o cattivo, ma consente alcune cose interessanti come reinterpretare i puntatori e i dati letti dai file.

  • Devi essere più consapevole dell'hardware su cui verrà eseguito il programma. Questo non è particolarmente correlato a C, ma a qualsiasi tipo di programmazione orientata alle prestazioni di basso livello. Più ti avvicini al metallo, più devi prestare attenzione a cose come l'utilizzo della cache della CPU, l'ingombro della memoria, i costi dell'IO dispositivo e la complessità del tempo dell'algoritmo. Ad esempio, potresti scoprire dopo la profilazione che una matrice semplice e una ricerca lineare sono più veloci di un albero di ricerca binario a causa di migliori schemi di accesso alla cache nell'architettura di destinazione.

  • Devi essere più consapevole dei dati, non solo del codice. Lo scopo di qualsiasi programma è quello di trasformare i dati, ma è facile lasciarsi trasportare dal codice e dalle astrazioni quando si scrivono interfacce di alto livello e dimenticare che il codice deve effettivamente elaborare alcuni dati e generare altri dati. Più conosci i tuoi dati, più diventa facile ottimizzare il codice, ovvero design orientato ai dati .

Questi sono alcuni aspetti interessanti da considerare. Certamente ce ne sono di più, ma è quello che posso pensare per il momento. Spero che non sia troppo scoraggiante. C è un ottimo linguaggio con cui lavorare, anche se personalmente mi piace C ++ meglio ;) . Anche la programmazione orientata alla prestazione di basso livello può essere molto divertente. Una volta entrato, vedrai la programmazione in un modo completamente nuovo.

    
risposta data 26.09.2015 - 07:59
fonte
4

La differenza tra tasto è la seguente:

  • Quando si effettua uno sviluppo di alto livello, si tratta principalmente di come risolvere un problema del mondo reale. Il tuo "dominio del problema" è una situazione reale, le tue entità sono entità del mondo reale e la tua logica è logica di applicazione . (Il termine "mondo reale" è alquanto flessibile, qui, poiché ad esempio potresti sviluppare un MMORPG, come World of Warcraft, nel qual caso il mondo è tutt'altro che reale, ma comunque, all'interno di quel contesto, questo è il mondo che sei trattando come reale.)

  • Quando si esegue lo sviluppo di basso livello, si tratta principalmente di come far sì che la macchina esegua un'attività specifica nel modo più efficiente possibile. Le entità con cui hai a che fare sono per lo più di natura altamente tecnica, come blocchi di memoria, catene di blocchi, valori hash, ecc. E la tua logica non ha nulla a che fare con il mondo reale e tutto ciò che riguarda la macchina. Ti occupi spesso di concetti completamente specifici della macchina, come endianness di parole macchina o porte I / O attraverso il quale puoi comunicare con un dispositivo specifico e le sequenze di bye che devi inviare per farlo svolgere il suo lavoro.

Di fatto, quando si interfaccia tra codice di alto livello e codice di basso livello, è spesso utile trasformare le entità di alto livello in entità di basso livello (o semplicemente visualizzare il primo come quest'ultimo, senza necessità di una vera trasformazione) in modo che il codice di alto livello non debba mai occuparsi di problemi di macchina, e il codice di basso livello non deve mai occuparsi dei problemi delle applicazioni.

Quindi, nella tua domanda potresti avere una collezione di, diciamo, clienti, e fare le cose con esso del tipo che facciamo con i clienti, come addebitarli per i beni acquistati, o inviare loro newsletter, senza preoccuparsi del rappresentazione interna della collezione. Nel tuo codice di basso livello, tuttavia, vedrai la raccolta come una serie di puntatori fissi agli oggetti, e potresti non sapere nulla su questi oggetti se non che potrebbero essere invocati per confrontarsi tra loro o per calcolare i propri valori hash. Non dovresti sapere che sono clienti e non devi inviare loro newsletter con codice di basso livello.

Quindi, se ti trovi a usare un linguaggio di basso livello come C, e dovendo trattare con entità applicative come "clienti", stai sbagliando. Ti è stato chiesto di usare la lingua sbagliata per il lavoro.

    
risposta data 26.09.2015 - 10:38
fonte
1

Essendo un programmatore C esperto e meno esperto di C ++ (ma ho codificato in progetti avviati da altre persone, non ho mai creato un progetto C ++ da zero, io stesso), potrei percorrere lo stesso percorso nella direzione opposta. Potremmo incontrarci nel mezzo da qualche parte e posso dirti un po 'di dove sono venuto.

Certamente ci sono funzionalità OOPsie del C ++ che C non ha. Ci sono problemi di namespace, modelli, ecc. Che non ho usato. Tutto ciò che ho fatto è usato e creato classi e oggetti istanziati all'interno delle classi. E codice modificato nelle classi create da altre persone.

Detto questo, ogni programmatore C può scrivere codice strutturato che è simile, per molti aspetti chiave, al codice OOP completo. Hai struct , typedef , puntatori a struct , la possibilità di lanciare il puntatore a una sorta di struct su un altro dove ci sono campi in comune. Esiste anche union in cui è possibile sovrapporre esplicitamente campi che sono in comune e altri campi che non sono in comune. Sembra molto simile a eredità che troverai in un linguaggio OOP.

Personalmente, non mi piacciono molte sintassi specifiche del C ++ che preferirei semplicemente programmare in C, dove so esattamente quale sia il modo "giusto" per farlo. Non conosco Java o C # o qualsiasi altra variante.

    
risposta data 26.09.2015 - 00:53
fonte
0

Principali differenze:

  • Sei responsabile di tutta la gestione delle risorse. Non esiste una garbage collection, né i buffer vengono estesi automaticamente se hai bisogno di più spazio. Questo include la gestione delle stringhe. C non ha un tipo di stringa in quanto tale; le stringhe sono memorizzate come matrici di char . Se vuoi aggiungere stringhe, devi assicurarti che il buffer di destinazione sia abbastanza grande prima di farlo.

  • Non esiste una gestione delle eccezioni strutturata. Errori e condizioni eccezionali sono indicati dai codici di ritorno delle funzioni o dalla scrittura di un parametro (o impostando errno ). È possibile eseguire il kind-of-sort di eccezioni false utilizzando le funzioni della libreria setjmp/longjmp , ma è un trucco al meglio.

  • C non ha limiti sulla verifica degli accessi agli array. Non ci sono eccezioni built-in per l'accesso a elementi al di fuori di un array. È ridicolmente facile da clobberare la memoria che non possiedi (come può essere visto da innumerevoli exploit nel corso degli anni).

  • I tipi di dati non sono intelligenti - gli array non sanno quanto sono grandi (perdono il loro "array" nella maggior parte dei contesti), i tipi di struct non hanno alcun tipo di metodo (puoi -sort-di falso usando i puntatori di funzione, ma non c'è un puntatore this implicito, devi dire esplicitamente a ciascuna funzione su quale istanza di struct operare).

  • Il codice è organizzato in moduli , piuttosto che in classi, in cui ogni modulo è costituito da definizioni di tipi, definizioni di oggetti e definizioni di funzioni. Non esiste un concetto di ereditarietà tra i moduli. La visibilità per i singoli elementi di dati e le sue funzioni è una proposizione "tutto o niente" - non esiste un equivalente per una visibilità "protetta".

  • Non ci sono tipi di contenitori oltre gli array. Se vuoi qualcosa di più sofisticato, dovrai eseguire il rollover o trovare una libreria container. Allo stesso modo, non ci sono algoritmi standard (come std::copy o std::foreach - di nuovo, dovrai far girare il tuo).

  • Non ci sono modelli, generici o altri meccanismi di digitazione dinamica. Non c'è sovraccarico di funzioni o operatori. Tutte le informazioni sul tipo devono essere note al momento della compilazione.

  • Non ci sono spazi per i nomi definibili dall'utente. C supporta un totale complessivo di quattro spazi dei nomi: etichette, nomi di tag, nomi di membri di sindacati e di tutto il resto.

È è possibile scrivere codice OO in C ; è solo un lotto di lavoro.

Pensa a C come a una sega da tavolo dall'aspetto sgradevole con bordi affilati, senza protezioni per le lame e cablaggi visibilmente logori, e sarai nella giusta mentalità.

    
risposta data 29.09.2015 - 01:09
fonte

Leggi altre domande sui tag