我有一个描述的结构:
#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
的{{1}}实例。
第二,我想把一个NULL指针放到ConnGraph
,但如果我解除bondStereo
,我会得到编译错误。更多,我的数据结构是否正确(#poke inchi_Atom, bond_stereo) $ nullPtr
?
答案 0 :(得分:1)
你可以为ConnGraph
制作一个可存储的实例,但它有点狡猾。通常的模式是为数组提供malloc空间并为其编组。但是,既然您知道最大大小,并且在结构中分配了空间,您可以利用这一点并写下:
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
成为新类型非常重要,因为此定义不会干扰[CShort]
类型的任何其他值。
您可以使用hsc2hs的#offset
宏来确定起始位置,然后在增量指针上使用pokeArray,而不是创建此Storable实例。这实际上看起来更容易:
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
的对齐方式相同,也可能不同,具体取决于您的系统。