Haskell: Come posso ottenere i valori delle costanti # define-d?
Domanda
In un programma Haskell, qual è il modo migliore per usare le costanti definite nelle intestazioni C?
Soluzione
Per questa attività, hsc2hs è il tuo amico.
Per un semplice esempio, otteniamo il valore di INT_MAX
da limits.h
.
$ cat >IntMax.hsc
module Main where
#include <limits.h>
c_INT_MAX = #const INT_MAX
main = print c_INT_MAX
Con hsc2hs, possiamo #include
e usare i valori delle costanti con la direttiva #const
.
Invece di costruire a mano, usa Cabal:
$ cat >intmax.cabal
Name: intmax
Version: 0.0
Cabal-Version: >=1.2
Build-Type: Simple
Executable intmax
Main-Is: IntMax.hs
Build-Depends: base
Nota che anche se il nome del programma principale è IntMax.hsc
, la linea Main-Is
punta a IntMax.hs
. Quando Cabal cerca IntMax.hs
ma trova IntMax.hsc
, alimenta automaticamente quest'ultimo tramite hsc2hs come parte della build.
$ cabal configure
Resolving dependencies...
Configuring intmax-0.0...
$ cabal build
Prerocessing executables for intmax-0.0...
Building intmax-0.0...
[1 of 1] Compiling Main ( dist\build\intmax\intmax-tmp\IntMax.hs, dist\build\intmax\intmax-tmp\Main.o )
Linking dist\build\intmax\intmax.exe ...
$ ./dist/build/intmax/intmax
2147483647
Nota che vorrai spezzare le linee con più costanti. Supponi che stai assemblando un bitfield per passare a FormatMessage . Ti consigliamo di scriverlo come
flags = #const FORMAT_MESSAGE_FROM_SYSTEM
.|.
#const FORMAT_MESSAGE_IGNORE_INSERTS
Metterli tutti su una riga comporterà errori di sintassi.
Altri suggerimenti
GHC si sta allontanando da -fvia-c
e verso -fasm
ove possibile.
Un effetto collaterale è che il tuo programma può essere compilato senza usare alcuna intestazione C, anche in modalità -fvia-c
, al fine di garantire che i risultati della compilazione siano funzionalmente identici a GHC in Modalità -fasm
.
Pertanto è necessario utilizzare hsc2hs
, c2hs
, o altri preprocessori eseguono prima di compilazioni di GHC.
c2hs
supporta nativamente le costanti enum
... è passato un po 'di tempo, ma penso che qualcosa del genere sia giusto.
#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc
{#enum Foo#}
somethingBar = {#call pure something#} (cFromEnum Bar)
Le costanti ?? #define
'd sono più complicate. Le ho sempre copiate in linea o utilizzate C aggiuntive per trasformarle in enum o variabili const.