2012-05-25 7 views
5

Vorrei chiamare una funzione C api da Fortran. La funzione C accetta un array di byte:Fortran: come memorizzare il valore 255 in un byte?

void image(const void *bitmap, int w, int h); 

dove tre byte successivi *bitmap rappresentano una tripla colore RGB e vengono interpretati come unsigned char in C. voglio inizializzare la bitmap in Fortran e curare disegno all'interno C . definizione attuale in Fortran utilizza

integer*1 rgbImage(6,2) 

per inizializzare l'immagine di 2x2 per esempio, ma compilatore non accetterà assegnazione

rgbImage(1,1) = 255 

per ottenere il colore rosso. Ho visto suggerimenti sull'uso di BYTE, UNSIGNED*1, LOGICAL*1 per singoli byte non firmati, ma gfortran (MacPort's gcc 4.4 o 4.6 in Mac OS X) non è davvero soddisfatto di nessuno dei due. Probabilmente potrei scappare barando e assegnando il valore -1 invece di 255, ma questo è molto scomodo da usare. Il flag del compilatore -fno-range-check ha aiutato a compilare il codice, ma potrebbe non essere disponibile in altri compilatori Fortran e lo considero una soluzione brutta (vorrei comunque rilevare altri avvisi). I valori 'FF'X o '11111111'B sono anche riconosciuti come numeri interi a 32 bit.

È altamente auspicabile che il codice sia portatile tra diversi compilatori Fortran.

+2

Fortran standard non supporta i tipi di numeri interi senza segno. Anche in 'ISO_C_BIDNING' non ci sono tipi che corrispondono a interi senza segno in C (eccetto per' C_SIZE_T' e 'C_INTPTR_T', ma sono ancora trattati come firmati in Fortran). Alcuni compilatori forniscono tipi senza segno come estensione della lingua. Quindi devi ricorrere a qualcosa come usare 'ACHAR()' come indicato da Jonathan Dursi. –

risposta

12

Il mio suggerimento sarebbe quello di utilizzare le variabili CHARACTER e utilizzare ACHAR per impostare valori (e ICHAR per riconvertire in numeri interi in base alle esigenze). Questo dovrebbe farti ottenere ciò che desideri ed essere completamente portatile. ad esempio,

character, dimension(6,2) :: rgbImage 

rgbImage(1,1) = achar(255) 

aggiornato per aggiungere: se avete intenzione di utilizzare la roba Fortran 2003 iso_c_binding per interfacciarsi con le routine C (! vivamente consigliato), allora si potrebbe anche fare che i caratteri di matrice rgbImage di tipo c_char, ad esempio

character(kind=c_char), dimension(6,2) :: rgbImage 
integer(kind=c_int) :: w, h 

... 
rgbImage(1,1) = achar(255) 
... 

call image(rgbImage, w, h) 

dove aver definito l'interfaccia per la routine

interface 
    subroutine image(img, w, h) bind(C) 
     use, intrinsic :: iso_c_binding 
     implicit none 
     integer(kind=c_int), intent(in), value :: w, h 
     character(kind=c_char) :: img(:,:) 
    end subroutine image 
end interface 
+0

Perfetto, grazie mille. – Mojca

+2

I tipi alternativi sono C_INT8_T (Fortran, ISO_C_Binding) e int8_t (C). Si potrebbe "imbrogliare" e usare uint8_t sul lato C anche se non corrisponde formalmente a C_INT8_T. Un altro possibile approccio ... –

0

Una strategia alternativa che può essere adatta per alcune circostanze è quella di passare l'array 1 byte c int a una matrice Integer (1), ad esempio iVal (:), quindi creare un altro array Int come Integer (2) iVal2 (:), poi:

Where(iVal(:) < 0) 
    iVal2(:) = -iVal(:)+127 
ElseWhere 
    iVal2(:) = iVal(:) 
End Where 

... questo può essere un po 'più efficiente/più pulita rispetto alla conversione a/caratteri fro (a volte) e richiede meno di codifica (a volte).

Se si esegue un sacco di questo tipo di cose (interfaccia di vari tipi di usigned, ecc. A Fortran), alcune routine di utilità basate sui bit intrinseca di Fortran possono essere un investimento utile (ad esempio BTest(), iBSet() ecc.) .