10. Comparação de tamanhos de variáveis
Em diversas ocasiões, principalmente em projetos que utilizam linguagens diferentes comunicando entre si, é necessário saber a diferença de tamanho entre diferentes tipos de variáveis para que não ocorra nenhum acesso indevido de memoria.
O exemplo dado nesse capítulo será entre C e Fortran, porém a ideia para outras linguagens é similar.
10.1 Macros utilizados
# configure.ac
AC_INIT([epp], [54.59])
m4_include([m4/checks.m4])
AC_PROG_CC
AC_PROG_FC
bcc=2
mb=1
bbb=0
define_c_sizes
define_fortran_sizes
epp_compare_sizes([c_int],
[$ac_cv_sizeof_int],
[fortan_int],
[$epp_fortran_sizeof_integer])
epp_compare_sizes([c_float],
[$ac_cv_sizeof_float],
[fortan_real],
[$epp_fortran_sizeof_real])
epp_compare_sizes([c_double],
[$ac_cv_sizeof_double],
[fortan_real],
[$epp_fortran_sizeof_real])
epp_compare_sizes([bcc], [$bcc], [bbb], [$bbb])
epp_compare_sizes([bcc], [$bcc], [mb], [$mb])
epp_compare_sizes([bbb], [$bbb], [mb], [$mb])
AC_OUTPUT
# m4/checks.m4
AC_DEFUN([define_c_sizes], [
AC_LANG_PUSH([C])
AC_CHECK_SIZEOF(int)
AC_CHECK_SIZEOF(long)
AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(float)
AC_CHECK_SIZEOF(double)
AC_CHECK_SIZEOF(int *)
AC_CHECK_SIZEOF(long *)
AC_CHECK_SIZEOF(long long *)
AC_CHECK_SIZEOF(float *)
AC_CHECK_SIZEOF(double *)
AC_LANG_POP([C])
])
AC_DEFUN([define_fortran_sizes], [
epp_fortran_sizeof([integer], [epp_fortran_sizeof_integer])
epp_fortran_sizeof([real], [epp_fortran_sizeof_real])
])
# $1 => Nome da primeira variável
# $2 => Valor da primeira variável
# $3 => Nome da segunda variável
# $4 => Valor da segunda variável
AC_DEFUN([epp_compare_sizes], [
AC_MSG_CHECKING(sizes of $1 vs $3)
AS_IF(
[test $2 -gt $4], [AC_MSG_RESULT($1 > $3)],
[test $2 -lt $4], [AC_MSG_RESULT($1 < $3)],
[AC_MSG_RESULT($1 == $3)]
)
])
AC_DEFUN([epp_fortran_sizeof], [
AC_LANG_PUSH([Fortran])
AC_MSG_CHECKING([size of Fortran $1])
AC_RUN_IFELSE([AC_LANG_PROGRAM([],
[[
$1 :: x
integer :: i
i = storage_size(x)/8
open(99, file='conftest.out', status='unknown')
write(99, '(I0)') i
close(99)
]])],
[eval $2=`cat conftest.out`],
[AC_MSG_RESULT(Compile errored out. Check config.log for more info)])
AC_MSG_RESULT($$2)
AC_LANG_POP([Fortran])
])
O exemplo acima segue um fluxo bem simples, começando por
configure.ac:
AC_PROG_CCeAC_PROG_FCpara garantir que o C e o Fortran estão inicializados antes de começar o programa- Definição de tamanhos de tipos de diferentes linguagens, além de um tipos sem sentido apenas para demonstrar que a função de comparação de tipos é agnóstica à linguagens
- Comparação entre os tamanhos, seguindo o estilo: nome da primeira variável, tamanho da primeira variável, nome da segunda variável, tamanho da segunda variável
Agora, seguindo m4/checks.m4:
define_c_sizes: macro simples pra definir os tipos C que serão utilizados. Para tipos C o Autoconf possui uma maneira pré-definida de conseguir o tamanho dos tipos, então usamos essa forma. A variável que guardará o tamanho dos tipos segue o estiloac_cv_sizeof_{tipo}define_fortran_sizes: macro para definir os tamanhos dos tipos do Fortran. Como o Autoconf não possui uma maneira nativa de obter os tipos do Fortran, é necessário definirmos a nossa forma, que será apresentada em breve. A variável que será usada para guardar o tamanho do tipo será da formaepp_fortran_sizeof_{tipo}epp_compare_sizes: macro para comparar os tamanhos obtidos. Pode também ser usada para comparar qualquer outros valores, pois o macro é apenas umif,else if,elsedentro doAS_IF, desde que siga a forma: nome da primeira variável, tamanho da primeira variável, nome da segunda variável, tamanho da segunda variável.AS_IFexecuta da seguinte forma:AS_IF([teste1], [roda-se-verdadeiro1], ..., [roda-se-todos-falsos]), seguindo uma cadeia deif,else ifdessa formaepp_fortran_sizeof: macro para obter o tamanho de tipos do Fortran. Como o Autoconf não possui forma nativa de obter tamanhos do Fortran, precisamos prover uma maneira nossa. A função segue a sequência de argumentos: tipo da variável, nome da variável onde o valor será guardado
A forma como o tamanho de um tipo é obtido em Fortran se
utiliza de um truque com arquivos no sistema. É declarado
uma variável x do tipo que foi passado e um inteiro i. O
tamanho do tipo de x é guardado em i e convertido em
bytes ao dividir por 8 (a função do Fortran retorna o valor
em bits). Após conseguir o tamanho, abrimos/criamos um
arquivo com o nome conftest.out e handle 99, escrevemos o
tamanho de i no arquivo e fechamos o arquivo.
Fora do Fortran, dentro do Autoconf, a função eval avalia
a expressão cat conftest.out para conseguir o valor
escrito pelo Fortran e o põe na variável passado que obterá
o tamanho pedido. No final, o valor obtido é mostrado no
console.
Com tudo isso apresentado, ao rodar o programa a saída será aproximadamente essa:
$ autoconf
$ ./configure
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...
checking whether we are cross compiling... no
checking for suffix of object files... o
checking whether the compiler supports GNU C... yes
checking whether gcc accepts -g... yes
checking for gcc option to enable C23 features... none needed
checking for gfortran... gfortran
checking whether the compiler supports GNU Fortran... yes
checking whether gfortran accepts -g... yes
checking for stdio.h... yes
checking for stdlib.h... yes
checking for string.h... yes
checking for inttypes.h... yes
checking for stdint.h... yes
checking for strings.h... yes
checking for sys/stat.h... yes
checking for sys/types.h... yes
checking for unistd.h... yes
checking size of int... 4
checking size of long... 8
checking size of long long... 8
checking size of float... 4
checking size of double... 8
checking size of int *... 8
checking size of long *... 8
checking size of long long *... 8
checking size of float *... 8
checking size of double *... 8
checking size of Fortran integer... 4
checking size of Fortran real... 4
checking sizes of c_int vs fortan_int... c_int == fortan_int
checking sizes of c_float vs fortan_real... c_float == fortan_real
checking sizes of c_double vs fortan_real... c_double > fortan_real
checking sizes of bcc vs bbb... bcc > bbb
checking sizes of bcc vs mb... bcc > mb
checking sizes of bbb vs mb... bbb < mb
configure: creating ./config.status
Caso a sua saída seja próxima a essa, o programa está funcionando perfeitamente.