2

我有一个描述的结构:

#define MAXVAL                   20 
#define ATOM_EL_LEN               6 
#define NUM_H_ISOTOPES            3 
typedef signed char   S_CHAR;
typedef unsigned char U_CHAR;
typedef signed short   S_SHORT;
typedef unsigned short U_SHORT;

typedef  S_SHORT AT_NUM;  

typedef struct tagInchiAtom {
    /* atom coordinates */
    double x;
    double y;
    double z;
    /* connectivity */
    AT_NUM  neighbor[MAXVAL];     /* adjacency list: ordering numbers of */
                                  /*            the adjacent atoms, >= 0 */
    S_CHAR  bond_type[MAXVAL];    /* inchi_BondType */
    /* 2D stereo */
    S_CHAR  bond_stereo[MAXVAL];  /* inchi_BondStereo2D; negative if the */
                                  /* sharp end points to opposite atom */
    /* other atom properties */
    char    elname[ATOM_EL_LEN];  /* zero-terminated chemical element name:*/
                                  /* "H", "Si", etc. */
    AT_NUM  num_bonds;            /* number of neighbors, bond types and bond*/
                                  /* stereo in the adjacency list */
    S_CHAR  num_iso_H[NUM_H_ISOTOPES+1]; /* implicit hydrogen atoms */
                                  /* [0]: number of implicit non-isotopic H
                                       (exception: num_iso_H[0]=-1 means INCHI
                                       adds implicit H automatically),
                                     [1]: number of implicit isotopic 1H (protium),
                                     [2]: number of implicit 2H (deuterium),
                                     [3]: number of implicit 3H (tritium) */
    AT_NUM  isotopic_mass;        /* 0 => non-isotopic; isotopic mass or  */
                                  /* ISOTOPIC_SHIFT_FLAG + mass - (average atomic mass) */
    S_CHAR  radical;              /* inchi_Radical */
    S_CHAR  charge;               /* positive or negative; 0 => no charge */
}inchi_Atom;

为了表示inchi_Atom我做了下面的数据结构:

type ConnGraph = [CShort]
data INCHIAtom = INCHIAtom {atoms :: ConnGraph,
                            label :: CString,
                            bondTypes :: ConnGraph,
                            charge :: CSChar}

然后,我尝试Storable为这个结构实现一个实例(使用hsc2hs):

instance Storable INCHIAtom where
    sizeOf    _ = (#size inchi_Atom)
    alignment _ = alignment (undefined :: CInt)
    peek _ = error "peek is not implemented"
    poke ptr (INCHIAtom atoms' label' bondType' charge') = do 
                                                          (#poke inchi_Atom, x) ptr $ (0 ::CDouble)
                                                          (#poke inchi_Atom, y) ptr $ (0 ::CDouble)
                                                          (#poke inchi_Atom, z) ptr $ (0 ::CDouble)
                                                          (#poke inchi_Atom, neighbor) ptr $ atoms'
                                                          (#poke inchi_Atom, bond_type) ptr $ bondType'
                                                          --(#poke inchi_Atom, bond_stereo) $ nullPtr
                                                          (#poke inchi_Atom, elname) ptr $ label'
                                                          (#poke inchi_Atom, num_bonds) ptr $ (length atoms')
                                                          (#poke inchi_Atom, num_iso_H) ptr $ (0 :: CSChar)
                                                          (#poke inchi_Atom, isotopic_mass) ptr $ (0 :: CShort)
                                                          (#poke inchi_Atom, radical) ptr $ (0 :: CSChar)
                                                          (#poke inchi_Atom, charge) ptr $ charge'

我有几个问题。我没有办法如何Storable实现ConnGraph. 其次,我想将一个 NULL 指针指向bondStereo,但是如果我取消注释,则会出现(#poke inchi_Atom, bond_stereo) $ nullPtr编译错误。更多,它对alignment (undefined :: CInt)我的​​数据结构是否正确?

4

1 回答 1

1

你可以为 Storable 创建一个实例ConnGraph,但它有点狡猾。通常的模式是为数组分配空间并对其进行编组。但是,由于您知道最大大小,并且在结构中分配了空间,您可以利用这一点并编写:

newtype ConnGraph = ConnGraph {unConnGraph :: [CShort]}

instance Storable ConnGraph where
    sizeOf _ = maxval*sizeOf (undefined :: CShort)
    alignment _ = alignment (undefined :: CShort)
    poke ptr (ConnGraph lst) = if length lst <= maxval
        then pokeArray (castPtr ptr) lst
        else error "Can't poke ConnGraph, too big!"

我对此并不完全满意,它似乎很脆弱。如果您想ConnGraph在结构外部编组inchi_Atom,可能会导致问题。如果你确实走这条路,我认为创建ConnGraph一个 newtype 很重要,因为这个定义不会干扰 type 的任何其他值[CShort]

您可以使用 hsc2hs 的#offset宏来确定起始位置,而不是创建这个 Storable 实例,然后在递增的指针上使用 pokeArray。这实际上看起来更容易:

pokeArray (ptr `plusPtr` (#offset inchi_Atom, neighbor)) $ unConnGraph atoms'

您可能应该检查长度是否不超过maxval此处。

在线错误的原因nullPtr是因为您遗漏了ptr参数。但是,此代码并非严格正确。如果您的指针类型大于short,您会将nullPtr值写入多个字段。更好的是明确清除整个数组。最终实例将是

-- I don't know how to do CPP in hsc2hs-generated Haskell, but you could create a separate module
-- that defines maxval = MAXVAL
maxval = 20

instance Storable INCHIAtom where
    sizeOf    _ = (#size inchi_Atom)
    alignment _ = alignment (undefined :: CDouble)
    peek _ = error "peek is not implemented"
    poke ptr (INCHIAtom atoms' label' bondType' charge') =
       do
          (#poke inchi_Atom, x) ptr $ (0 ::CDouble)
          (#poke inchi_Atom, y) ptr $ (0 ::CDouble)
          (#poke inchi_Atom, z) ptr $ (0 ::CDouble)
          (#poke inchi_Atom, neighbor) ptr $ atoms'
          (#poke inchi_Atom, bond_type) ptr $ bondType'
          (#poke inchi_Atom, bond_stereo) ptr $ ConnGraph (replicate maxval 0)
          (#poke inchi_Atom, elname) ptr $ label'
          (#poke inchi_Atom, num_bonds) ptr $ (length $ unConnGraph atoms')
          (#poke inchi_Atom, num_iso_H) ptr $ (0 :: CSChar)
          (#poke inchi_Atom, isotopic_mass) ptr $ (0 :: CShort)
          (#poke inchi_Atom, radical) ptr $ (0 :: CSChar)
          (#poke inchi_Atom, charge) ptr $ charge'

我还更改了对齐方式以匹配CDouble。结构的对齐方式至少与最严格的成员一样严格,在本例中为double. 这可能与 的对齐方式相同int,也可能不同,具体取决于您的系统。

于 2013-10-08T23:52:10.610 回答