Можно ли заставить строку определенного размера при определении структуры? - PullRequest
4 голосов
/ 06 октября 2009

Я сортирую данные между приложениями 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 ++ читает этот файл, и я буду анализировать его обратно в struct в C ++ с той же структурой. Моя первая попытка этой структуры выглядела так:

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

Но у компилятора нет возможности узнать, что я хочу, чтобы эта std :: string была 256 байтов.

edit: например, добавление полного файла заголовка.

#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 ]

6 голосов
/ 06 октября 2009

В общем, вы ошибаетесь. Смешивание не-данных только типов C ++ и PInvoke принесет вам много боли. Такие типы, как std :: string, не должны использоваться в этом сценарии, поскольку маршаллер не может их правильно создать во время выполнения.

Вместо этого вам нужно использовать больше примитивных типов. В этом конкретном сценарии, на основе управляемой подписи, подходящей структурой C является следующая

struct DataLocater
{
    char filename[256];
    int sizeOfData;
    int startLocation;
    int encrypted;
};
6 голосов
/ 06 октября 2009

Это то, что вы ищете?

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

edit: Учтите, что вам НЕ НУЖНО принудительно указывать какую-либо строку определенного размера, вы можете объявить имя файла как char *, а для размера C # использовать строку без ограничений. Таким образом, вы бы использовали столько памяти, сколько необходимо (и, возможно, использовали бы больше, чем предполагалось изначально, избегая ошибок переполнения буфера).

2 голосов
/ 06 октября 2009

Вы не можете маршалировать массивы C # непосредственно в std::string. Строковый класс имеет целый ряд других вещей в своем пространстве памяти, кроме необработанных символьных данных: указатель vtable, спецификатор длины, возможно, также кучу других вещей.

Необходимо указать параметр имени файла в виде wchar [256], а затем преобразовать wchar[256] в std::string.

1 голос
/ 06 октября 2009

Std :: string не имеет фиксированной длины и, как правило, хранит свои данные не в выделенном пространстве, а в куче. Требуется массив символов или байтов фиксированной длины в зависимости от кодировки структуры.

Сокращение примеров на MSDN для ByValTStr использования дает три:

// 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;
}
...