在定义结构时是否可以强制字符串为特定大小?

时间:2009-10-05 22:27:40

标签: c++ string struct pinvoke marshalling

我在C#和C ++应用程序之间编组数据。在C#应用程序中,我强制将字符串的大小设置为某个大小(例如,256字节)。我想在C ++中读取完全相同的数量(我将使用reinterpret_cast重新创建结构),以便数据保持格式化,就像在C#应用程序中一样。不幸的是,我对C ++很生疏,我不知道如何在C ++中强制使用字符串的大小。

根据要求,举个例子。我在C#中有一个结构,如下所示:

[StructLayout(LayoutKind.Sequential)]
        public struct DataLocater
        {
            [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
            public string filename;
            [MarshalAs(UnmanagedType.I4)]
            public Int32 sizeOfData;
            public Int32 startLocation;
            public Int32 encrypted;
        }

我正在将数个(连同其他数据)编组到数据文件中。然后C ++文件读取此文件,我将使用相同的结构将其解析回C ++中的struct。我对这个结构的第一次尝试看起来像:

struct DataLocater
{
    std::string filename;
    int sizeOfData;
    int startLocation;
    int encrypted;
};

但编译器无法知道我希望std :: string为256字节。

编辑:例如添加完整的头文件。

#pragma once
#include "CoreArea/Singleton.h"

class FileReader : public Singleton<FileReader>
{
    friend class Singleton<FileReader>;

public:
    void* GetFileData(std::wstring fileName, int &size);

private:
    FileReader();
    ~FileReader();

    struct Header
    {
        std::string somestring;
        int numOfFiles;
    };

    struct DataLocater
    {
        char[256] filename;
        int sizeOfData;
        int startLocation;
        int encrypted;
    };
};

4 个答案:

答案 0 :(得分:6)

这是你在找什么?

struct DataLocater
{
        char filename[256];
        int sizeOfData;
        int startLocation;
        int encrypted;
};

编辑:考虑到你不需要强制任何一个字符串具有一定的大小,你可以将文件名声明为char *,而在C#大小上你要使用一个没有限制的字符串。这样你只需要使用尽可能多的内存(并且可能使用比你最初估计的更多,避免缓冲区溢出错误)。

答案 1 :(得分:6)

一般来说,你在这里采取了错误的做法。混合非数据只有C ++类型和PInvoke将带来很多痛苦。不应在此场景中使用类似std :: string的类型,因为编组器无法在运行时正确创建它们。

相反,您需要使用更原始的类型。在此特定方案中,基于托管签名,适当的C结构如下

struct DataLocater
{
    char filename[256];
    int sizeOfData;
    int startLocation;
    int encrypted;
};

答案 2 :(得分:2)

您无法直接将C#数组编组到std::string中。除了原始字符数据之外,字符串类在其内存空间中还有一大堆其他东西:vtable指针,长度说明符,也可能是其他一些东西。

您需要将filename参数指定为wchar [256],然后将wchar[256]转换为std::string

答案 3 :(得分:1)

std :: string的长度不固定,通常不会将其数据存储在已分配的空间中,而是存储在堆中。您需要一个固定长度的字符或字节数组,具体取决于结构的字符集。

修改MSDNByValTStr使用的示例会给出这三个:

// C 
struct StringInfoA {
   char      f2[256];
};
struct StringInfoW {
   WCHAR     f2[256];
};
struct StringInfoT {
   TCHAR     f2[256];
};

对应

// C#
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Ansi)]
struct StringInfoA {
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
struct StringInfoW {
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Auto)]
struct StringInfoT {
   [MarshalAs(UnmanagedType.ByValTStr, SizeConst=256)] public String f2;
}