Haskell: Как я могу получить значения констант #define-d?

В программе на Haskell, как лучше всего использовать константы, определенные в заголовках C?

2 ответа

Решение

Для этой задачи hsc2hs - ваш друг.

Для простого примера, давайте получим значение INT_MAX от limits.h,

$ cat >IntMax.hsc
module Main where

#include <limits.h>

c_INT_MAX = #const INT_MAX

main = print c_INT_MAX

С помощью hsc2hs мы можем #include заголовки и использовать значения констант с #const директивы.

Вместо того, чтобы строить вручную, используйте 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

Обратите внимание, что хотя имя основной программы IntMax.hsc, Main-Is линия указывает на IntMax.hs, Когда Кабала ищет IntMax.hs но находит IntMax.hsc, он автоматически передает последний через hsc2hs как часть сборки.

$ 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

Обратите внимание, что вы хотите разбить строки с несколькими константами. Допустим, вы собираете битовое поле для передачи в FormatMessage. Вы хотите написать это как

flags = #const FORMAT_MESSAGE_FROM_SYSTEM
        .|.
        #const FORMAT_MESSAGE_IGNORE_INSERTS

Помещение их всех в одну строку приведет к синтаксическим ошибкам.

GHC удаляется от -fvia-c и к -fasm где это возможно.

Одним из побочных эффектов является то, что ваша программа может быть скомпилирована без использования каких-либо заголовков C, даже в -fvia-c режим, чтобы гарантировать, что результаты компиляции функционально идентичны GHC в -fasm Режим.

Таким образом, необходимо использовать hsc2hs, c2hsили другие препроцессоры запускаются до того, как GHC скомпилирует источники.

c2hs изначально поддерживает enum константы... это было давно, но я думаю, что-то вроде этого правильно.

#c
enum Foo = { Bar, Baz };
void something(enum Foo foo) {}
#endc

{#enum Foo#}

somethingBar = {#call pure something#} (cFromEnum Bar)

#defineконстанты бывают хитрее. Я всегда просто копировал их в строку или использовал дополнительный C для преобразования затем в перечисления или константы.

Другие вопросы по тегам