Newsgroup: it.comp.lang.c++
Titolo: Codice portabile

Salve a tutti,
sto scrivendo una libreria in C++ e vorrei che fosse portabile il più
possibile (mi interessano architetture che montano sistemi operativi
come Windows, Linux, MacOSX e anche quelli mobile come Symbian,
Android, Bada, WindowsME).
Ciò che mi preoccupa maggiormente è l'accesso ai file. Alcuni metodi
della libreria necessitano di dati che vanno salvati su file. Le
opzioni che mi vengono in mente sono
1]
Lasci all'utente programmatore il compito di scrivere una funzione del
tipo LoadData(). Il puntatore ai dati caricati verrà passato alla
libreria per
l'inizializzazione di  un determinato oggetto.
2]
Questo secondo metodo l'ho usato finora, ma non mi convince. L'idea è
quella di avere una classe SFileSystem statica, tramite la quale la
libreria, quando deve accedere ad un file, richiede un puntatore al
File System correntemente installato. Quindi SFileSystem avrà al suo
interno un metodo
denominato:
static	IFileSystem	*GetFileSystem();
e IFileSystem è una classe virtuale che ha metodi tipo Open(), Read()
e così via. L'implementazione di default di IFileSystem è quella che
usa la stdio.h. Se tale possibilità non è supportata dal sistema
operativo su cui si usa la libreria, l'utente programmatore dovrà
implementare una classe
derivata da IFileSystem appropriata, registrarla come File System
correntemente installato e continuare ad usare la libreria.
La libreria userà quindi il file system installato e creato dal
programmatore e non quello di default.
3]
Scrivere una versione della libreria compilata per ogni piattaforma
supportata (leggi: dare tutte le implementazioni necessarie di
IFileSystem e
compilare diverse versione della stessa libreria).
Che metodo mi suggerireste? Ora che ho scritto questo post, mi sono
convinto che la 3] è la soluzione migliore :)
Un'altra domanda che ho è la seguente: è bene preoccuparsi per
l'endianness? Voglio dire, i cellulari di solito hanno una CPU ARM,
che ha lo stesso byte-ordering delle cpu Intel, quindi coprirei
un'ampia quantità di dispositivi...
Avete qualche link/libro da suggerirmi che considerate un must per
scrivere codice portabile?
Grazie,
Luca

 scrivere codice portabile?
Uhm, no, nulla in particolare, c'è una letteratura vastissima su 
internet e basta fare un paio di ricerche per trovare tonnellate di 
riferimenti in inglese (ma anche quelli in italiano non mi sembra siano 
pochi, data la basilarità del problema).
-- 
  FSC - 
http://userscripts.org/scripts/show/59948
 
http://fscode.altervista.org
 - 
http://sardinias.com

 pochi, data la basilarità del problema).
Ok, grazie!

 ai file tramite lo standard ANSI C o C++.
A quel punto scriviti una tua funzione di lettura (es. myread()), una
di scrittura (es. mywrite()), e così via, e crea tanti file cpp in cui
le implementi in maniera diversa in base all'architettura che userai.
A questo punto tramite degli #include appropriati (che dipendono da
uno/pochi header di configurazione) selezionerai il modulo adatto in
fase di compilazione, e se tutto il progetto usa le myread(),
mywrite(), ecc. stai ben certo che diventa portabile.
Piuttosto io non lascerei al programmatore l'onere di creare un
descrittore file da passare alle tue funzioni, piuttosto scriverei le
funzioni in modo di ricevere in input dal programmatore solo il
percorso sotto forma di stringa o char *.
Ad esempio puoi crearti una
  int myfopen(string path);
che prenda in input il percorso ed al suo interno apra il file in base
alla piattaforma.
A quel punto su windows il programmatore avrà un:
int f = myfopen("c:\\pippo.txt")
mentre su *nix
int f = myfopen("mypath/myfile.txt")
le myread(), mywrite() e myclose() accetteranno l'intero restituito da
myopen() ed il gioco è fatto. Resti in casa tua praticamente visto che
quell'intero lo ha generato comunque una tua funzione.
Per l'endianness non saprei proprio che dirti.
Comunque se guardi bene in giro molti progetti multi-piattaforma sono
scaricabili proprio in base alla piattaforma di destinazione, segno
che non è sempre possibile la portabilità *totale* e completa.

 convinto che la 3] č la soluzione migliore :)
Una osservazione.
Sě, d'accordo, tu crei una funzione della tua lib con lo stesso nome che 
su tutte le piattaforme/filesystem apre un file.
Ma filesystem diversi hanno opinioni diverse su come un file puň 
chiamarsi, su quali permessi puň avere, su quanto puň essere lungo 
eccetera.
Per cui lo sforzo che stai facendo lo vedo utile solo se "ti accontenti" 
di aprire un file, leggerlo e chiuderlo. Anche sulla endianness vale un 
discorso simile. Cioč meno dettagli prendi in considerazione, piů 
operazioni "nascondi dietro le quinte" meglio č: IMHO se vuoi che la tua 
lib possa occuparsi di *tutti* i dettagli implementativi possibili su 
*tutte* le piattaforme, faresti meglio a considerare una struttura tipo:
- Main Library, con le funzioni di uso normale piů astratte e astraibili 
tipo apri-chiudi-leggi-scrivi, con un solo sorgente per tutte le 
piattaforme;
- Companion Libraries, con le funzioni piů dipendenti dalla piattaforma 
(setta permessi, elenca directories, converti nomi file ecc.) con 
sorgenti diversi per ciascuna piattaforma.
Per me cosě avrebbe piů senso... no?

 Per me così avrebbe più senso... no?
Ciao,
allora, la libreria si occupa fondamentalmente di fornire una serie di
funzioni che lavorano su immagini W x H a scala di grigi.
Ora, il problema è che alcune di queste operazioni necessitano di una
fase off-line. Ipotizziamo che una classe in particolare richieda
informazioni generate off-line.
L'utente dovrà quindi:
tramite un tools fornito da me, sul tuo PC, processare dei dati e
creare un file mydata.data
Per lavorare con un oggetto di tale classe bisogna passargli le
informazioni contenute in mydata.data. Tutto qui. Non ho bisogno di
interagire in modo
particolare con il file system. Il metodo che ho progettato in effetti
funziona e risulta comodo per un motivo.
Io compilo la libreria corredata di una classe che implementa
operazioni di read/write basate sulle funzioni che si trovano in
stdlib.h (oppure sugli stream, non fa differenza).
Dopodiché, usando lo stesso .lib, posso scrivere dei miei semplici
gestori di file a parte, che rispettino l'interfaccia IFileSystem ed i
comportamenti attesi dalle funzioni virtuali
in essa definite e posso "installarli"a run-time. Ovvero, per un
sistema operativo come Symbian, l'utente riceve il .lib della libreria
e un sorgente a parte che implementa IFileSystem.
Poi, ci sarà una fase di inizializzazione  in cui l'utente dovrà
settare come file system da usare quello appropriato del Symbian (una
chiamata ad una funzione...).
La libreria userà il file system settato, quindi tutto funzionerà.
Perché tutto questo? Se rendo tutto trasparente all'utente, ovvero mi
occupo IO di scrivere questi piccoli gestori di file system, è chiaro
che la libreria funzionerà solo sui sistemi
operativi supportati preventivamente da me.
Se, d'altro canto, lascio la possibilità all'utente di implementare il
semplice file system appropriato al suo sistema, possono ancora dare
supporto preventivo ad alcuni di essi,
però comunque tutti i sistemi operativi per i quali uno possa
sviluppare in C++ ANSI potranno usare la libreria (a quel punto, forse
solo l'endianness è un problema).
Luca


Se mi posso permettere il metodo migliore per ottenere un codice
portabile è usare una
libreria come boost. La libreria offre per i principali SO tutte le
funzioni necessarie. Dai thread
al filesystem.
Tieni presente che boost fra le varie possibili è la più utilizzata
dal programmatori c++ ed
è pure l'anticamera dello standard c++. Unica controindicazione ci
vuole un
po' di pazienza e perseveranza per impararla ma i risultati sono
garantiti.
Luca