2009-10-05 11 views
4

Je rassemble des données entre une application C# et C++. Dans l'application C#, je force la taille d'une chaîne à une certaine taille (disons, 256 octets). Je voudrais lire exactement la même quantité en C++ (je vais recréer les structures avec reinterpret_cast) pour que les données restent formatées comme dans l'application C#. Malheureusement, je suis assez rouillé avec C++ et je ne sais pas comment forcer la taille d'une chaîne dans une structure en C++.Est-il possible de forcer une chaîne à avoir une taille spécifique lors de la définition d'une structure?

Comme demandé, un exemple. J'ai un struct en C# qui ressemble à ceci:

[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; 
     } 

que je mobilisons plusieurs (ainsi que d'autres données) à un fichier de données. Le fichier C++ lit alors ce fichier et je vais l'analyser de nouveau en struct en C++ avec la même structure. Ma première tentative de ce struct ressemblait à:

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

Mais il n'y a aucun moyen pour le compilateur de savoir que je veux que std :: string soit 256 octets.

modifier: ajouter un fichier d'en-tête complet par exemple.

#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; 
    }; 
}; 
+1

Il n'y a pas question ici. Astuce: les questions se terminent par un point d'interrogation (?). – abelenky

+0

La question est dans le titre. Le corps contient une description. – Chris

+5

Indice: le titre de la question se termine par un point d'interrogation –

Répondre

6

En général, vous prenez la mauvaise approche ici. Le mélange de types C++ non-data et de PInvoke vous causera beaucoup de souffrance. Des types comme std :: string ne doivent pas être utilisés dans ce scénario car le marshaller ne peut pas les créer correctement lors de l'exécution. A la place, vous devez utiliser des types plus primitifs. Dans ce scénario, basé sur la signature gérée, la struct C appropriée est la suivante

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

@Downvoter, un commentaire? – JaredPar

+0

comme indiqué ci-dessus, en déclarant char [256] donne une erreur "bloc d'attribut vide n'est pas autorisé". C'était mon raisonnement initial pour essayer ma main sur std :: string. Bon conseil sur les types de mixage, cependant. – Chris

+0

@Chris, je ne sais pas pourquoi cela se passe mais ce n'est pas lié à la signature. La structure DataLocator est un code C++ valide (vérifié sur VS2008 RTM) – JaredPar

6

Est-ce ce que vous cherchez?

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

edit: Considérez que vous n'avez pas besoin de forcer soit chaîne à être d'une certaine taille, vous pouvez déclarer le nom de fichier comme char * et la taille C# vous souhaitez utiliser une chaîne sans restriction. De cette façon, vous n'utiliserez que la quantité de mémoire nécessaire (et utiliserez peut-être plus que ce que vous avez initialement estimé, évitant ainsi les erreurs de dépassement de tampon).

+0

Cela m'a semblé logique et a été ma première tentative. Cependant, il m'a lancé toute une série d'erreurs, la première étant: l'erreur C3409: le bloc d'attribut vide n'est pas autorisé. J'ai supposé à ce point, que vous ne pourriez pas lui donner une taille dans la structure. J'ai besoin d'une taille d'ensemble pour faciliter la lecture des fichiers, et dans le cadre des spécifications. – Chris

+0

Juste testé dans VS2008 et il compilé sans problème. Essayez de montrer exactement ce que vous essayez de compiler (le tout) afin que nous puissions voir votre erreur. – Blindy

+0

Intéressant. J'ai ajouté le contenu du fichier d'en-tête complet au bas de la publication. – Chris

2

Vous ne pouvez pas rassembler les tableaux C# directement dans un std::string. La classe de chaînes a tout un tas d'autres choses dans son espace mémoire à côté des données de caractère brutes: pointeur vtable, spécificateur de longueur, probablement aussi un tas d'autres choses.

Vous devez spécifier le paramètre filename en tant que wchar [256], puis convertir le wchar[256] en std::string.

1

Une chaîne std :: string n'a pas une longueur fixe et ne stocke généralement pas ses données dans son espace alloué, mais dans le tas. Vous voulez un tableau de longueur fixe de caractères ou d'octets, en fonction du jeu de caractères de la structure.

Élagage les exemples sur MSDN pour ByValTStr utilisation donne ces trois:

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

qui correspondent à

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