2012-05-25 23 views
5

Me gustaría llamar a una función C api de Fortran. La función C acepta una matriz de bytes:Fortran: ¿Cómo almacenar el valor 255 en un byte?

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

donde tres bytes sucesivos en *bitmap representan un tripple de color RGB y se interpretan como unsigned char en C. I desea inicializar el mapa de bits en Fortran y cuidar de dibujo dentro de C . definición actual en Fortran utiliza

integer*1 rgbImage(6,2) 

para inicializar una imagen de 2x2 por ejemplo, pero compilador no aceptar la asignación

rgbImage(1,1) = 255 

para obtener el color rojo. He visto indicios de usar BYTE, UNSIGNED*1, LOGICAL*1 para bytes individuales sin signo, pero gfortran (gcc 4.4 o 4.6 de MacPort bajo Mac OS X) no está contento con ninguno de ellos. Probablemente podría escapar engañando y asignando valor -1 en lugar de 255, pero eso es muy incómodo de usar. La bandera del compilador -fno-range-check ayudó a compilar el código, pero podría no estar disponible en otros compiladores de Fortran y considero que es una solución desagradable (todavía quisiera ver otra advertencia). Los valores 'FF'X o '11111111'B también se reconocen como enteros de 32 bits.

Es muy deseable que el código sea portable en diferentes compiladores Fortran.

+2

Estándar Fortran no admite tipos enteros sin signo. Incluso en 'ISO_C_BIDNING' no hay tipos que correspondan a enteros sin signo en C (a excepción de' C_SIZE_T' y 'C_INTPTR_T' pero todavía se tratan como firmados en Fortran). Algunos compiladores proporcionan tipos sin firmar como una extensión del idioma. Entonces tienes que recurrir a algo como usar 'ACHAR()' como señaló Jonathan Dursi. –

Respuesta

12

Mi sugerencia sería usar variables CHARACTER, y usar ACHAR para establecer valores (y ICHAR para convertir de nuevo a números enteros según sea necesario). Eso debería darte lo que quieres y ser completamente portátil. por ejemplo,

character, dimension(6,2) :: rgbImage 

rgbImage(1,1) = achar(255) 

actualizado para añadir: si se va a utilizar el material Fortran 2003 iso_c_binding para interconectar a las rutinas C (! muy recomendable) a continuación, que también podría hacer que los caracteres de matriz rgbImage de tipo c_char, por ejemplo

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

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

call image(rgbImage, w, h) 

donde se haya definido la interfaz de la rutina

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

Perfecto, muchas gracias. – Mojca

+2

Los tipos alternativos son C_INT8_T (Fortran, ISO_C_Binding) e int8_t (C). Uno podría "hacer trampa" y usar uint8_t en el lado C aunque no coincida formalmente con C_INT8_T. Otro posible enfoque ... –

0

Una estrategia alternativa que puede ser adecuada para algunas circunstancias es pasar la matriz 1 byte c int a una matriz Integer (1), por ejemplo, iVal (:), luego crear otra matriz Int como Integer (2) iVal2 (:), entonces:

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

... esto puede ser un poco más eficiente/limpiador en comparación con la conversión a/caracteres para (a veces) y requiere menos codificación (a veces).

Si haces mucho de este tipo de cosas (interconectando varios tipos de usuarios, etc. a Fortran), algunas rutinas de utilidad que dependen de los bits intrínsecos de Fortran pueden ser una inversión que valga la pena (por ejemplo, BTest(), iBSet(), etc.) .

Cuestiones relacionadas