c#中的char []数组相当于

时间:2012-05-24 15:12:07

标签: c# c++ pinvoke

我有一个c ++结构,它的char [20]如下所示,它是打包的。

#pragma pack(push, temp_aion_packed, 1)
struct temp
{
  char x[20];
  char y[20];
};
#pragma pack(pop, temp_aion_packed)

现在我如何在c#中编写这个结构,以便两者都相同。我在c#

中写过这样的文字
[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public class temp
{
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
     public string x;
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
     public string y;
}
下面的

是c#

中的pinvoke声明
[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
    public static extern int OrderRequirement(ref temp tmp);

c ++函数,将此结构称为参数

long __stdcall OrderRequirement(struct temp *tmp)
{
  string p="";
  string q="";
  p=temp->x;
  q=temp->y;
  char buff[2048];
  sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);
 }

但是当我在c#中这样做的时候,它给了我c ++中的垃圾数据,当我在c#中为它们赋值时。请任何人协助。

谢谢大家对上述方面的帮助,但现在我遇到了一个新问题,这是一个新的问题,我将在下面详细介绍。

我在c ++中的结构

#pragma pack(push, temp_aion_packed, 1)
struct temp
{
  long req;
  struct type m_type;
  short id;
  char x[20];
  char y[20];
};
#pragma pack(pop, temp_aion_packed)

#pragma pack(push, type_aion_packed, 1)
struct type
{
  short i;
};
#pragma pack(pop, type_aion_packed)

我写过像这样的等效c#结构

[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct temp
{
   [DataMember]
    public long req;
   [DataMember]
    [MarshalAs(UnmanagedType.Struct)]
     public type m_type;
   [DataMember]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
     public string x;
   [DataMember]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
     public string y;
}

[DataContract]
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct type
{
  [DataMember]
    public short i;
}
下面是我的c#pinvoke

[DllImport("rmsCAPI.dll", CallingConvention = CallingConvention.StdCall, ExactSpelling = true, EntryPoint = "OrderRequirement")]
    public static extern int OrderRequirement(ref temp tmp);

下面是我的c ++方法,它将struct作为参数

long __stdcall OrderRequirement(struct temp *tmp)
{
  char buff[2048];
  sprintf(buff,"req: %ld \n id: %d \n x: %s\n",tmp->req,tmp->id,tmp->x);
}

现在我遇到的问题是因为我在struct temp中声明了结构变量m_type(结构“type”),在我的c ++程序中打印的变量(long req)之前声明的变量,但是之后声明的变量没有给我任何输出。所以我认为c#中的结构声明搞砸了,我无法弄清楚,所以任何人都可以帮忙。

1 个答案:

答案 0 :(得分:1)

您在C#中将结构声明为一个类。这很好,但这意味着该类型的任何变量都已经是一个参考。所以你不需要经过ref。当你通过ref传递一个类时,你最终会传递一个指向该对象的指针。这是间接的一个层次太多了。

C#代码中的P / invoke应该是这样的:

public static extern int OrderRequirement(temp tmp);

另一种解决方法是将ref保留在函数声明中,但要将temp类型声明为struct而不是class。这是因为struct是值类型。类型为结构的变量是值而不是引用。

两种解决方案都有效,取决于您的选择。


您的C ++代码中还有另一个问题。

sprintf(buff,"p: %s\n q: %s\n x: %s\n y: %s\n",p,q,temp->x,temp->y);

您正在将pq std::string传递给printf,并希望%s格式字符串可以打印它们。那是一个错误。您需要在字符串上调用c_str()。像这样:

sprintf(
  buff,
  "p: %s\n q: %s\n x: %s\n y: %s\n",
  p.c_str(),q.c_str(),temp->x,temp->y
);

更新的问题是Windows C ++中的长度为32位,C#中为64位。您需要在C#中将其声明为int。你完全错过了id字段。

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1),Serializable]
public struct temp
{
    [DataMember]
    public int req;

    [DataMember]
    public type m_type;

    [DataMember]
    public short id;

    [DataMember]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string x;

    [DataMember]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 20)]
    public string y;
}