Dans un programme Haskell, quelle est la meilleure façon d'utiliser les constantes définies dans les en-têtes C?Haskell: Comment obtenir les valeurs de # define-d constantes?
Répondre
Pour cette tâche, hsc2hs est votre ami. Pour un exemple simple, prenons la valeur INT_MAX
de limits.h
.
$ cat >IntMax.hsc
module Main where
#include <limits.h>
c_INT_MAX = #const INT_MAX
main = print c_INT_MAX
Avec hsc2hs, nous pouvons #include
les en-têtes et d'utiliser les valeurs des constantes de la directive #const
.
au lieu de construire à la main, utilisez 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
Notez que même si le nom du programme principal est IntMax.hsc
, les points de ligne Main-Is
à IntMax.hs
. Lorsque Cabal cherche IntMax.hs
mais trouve IntMax.hsc
, il alimente automatiquement ce dernier via hsc2hs dans le cadre de la construction.
$ 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
Notez que vous aurez envie de briser les lignes avec plusieurs constantes. Supposons que vous assemblez un champ de bits pour passer à FormatMessage. Vous aurez besoin de l'écrire comme
flags = #const FORMAT_MESSAGE_FROM_SYSTEM
.|.
#const FORMAT_MESSAGE_IGNORE_INSERTS
Si vous les mettez tous sur une ligne, cela entraînera des erreurs de syntaxe.
GHC s'éloigne de -fvia-c
et vers -fasm
autant que possible. Un effet secondaire est que votre programme peut être compilé sans utiliser d'en-têtes C, même en mode -fvia-c
, afin de garantir que les résultats de compilation sont fonctionnellement identiques à GHC en mode -fasm
.
Il est donc nécessaire d'utiliser hsc2hs
, c2hs
, ou d'autres préprocesseurs exécuter avant GHC compile les sources.
c2hs
supporte nativement enum
constantes ... ça fait longtemps, mais je pense que quelque chose comme ça est juste.
#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc
{#enum Foo#}
somethingBar = {#call pure something#} (cFromEnum Bar)
#define
« constantes d sont une tique plus délicate. Je les ai toujours simplement copiés en ligne, ou utilisé des C supplémentaires pour les transformer en enums ou const variables.