2009-03-20 7 views
1

Salutations Tout le monde.Accès à la mémoire de classe publique à partir de C++ en utilisant C

Je suis en train d'écrire un programme multi-langage en C, C++ et fortran sous UNIX, malheureusement je rencontre une erreur de segmentation quand j'essaie de l'exécuter après la compilation.

J'ai réduit le problème à l'interface entre les sections C++ et C de mon programme. La première section se compose de main.ccp et SA.cpp, et la seconde CFE.c.

Une classe appelée 'SimAnneal' existe dans SA.cpp, avec les vecteurs publics DensityArray et ElementArray. L'ordre du programme suit:

  1. Créer SimAnneal objet 'Obj1' et la fonction d'appel ObjFunction()

  2. Cette fonction initialise le vecteur tailles

  3. Appel CFE (...) avec des pointeurs vers les deux vecteurs et leur longueur.

  4. CFE.c édite les éléments de données des vecteurs directement via l'utilisation des pointeurs

  5. ObjFunction() utilise les données EnergyArray (et DensityArray possibles).

Le script est pertinent ci-dessous pour toutes les sources:

main.cpp

#include "SA.h" 

int main() 
{ 
    SimAnneal Obj1; 

    Obj1.ObjFunction(); 

    return 0; 
} 

SA.h

class SimAnneal 
{ 
    void Initialize(); 
    ... 
    public 
    std::vector<float> DensityArray; 
    std::vector<float> EnergyArray; 
    double ObjFunction(); 
    ... 
} 

SA.cpp

#include "CFE.h" 

void SimAnneal::Initialize() 
{ 
    int length = 15; 
    EnergyArray.resize(length); 
DensityArray.resize(length); 
} 

double SimAnneal::ObjFunction() 
{ 
    Initialize(); 

    CFE(&DensityArray[0], &EnergyArray[0], DensityArray.size()); 

     // sends pointers of both arrays to CFE.c, which will then 
     // directly modify the array 

    double SumStrainEnergy = 0; 

    for (int i = 0; i < EnergyArray.size(); i++) 
    { 
     SumStrainEnergy += EnergyArray[i]; //Effectively sum of array 
              //engy[] from CFE.c 
    } 

    return SumStrainEnergy; 
} 

CFE.h

#ifdef __cplusplus 
extern "C" { 
#endif 

void CFE(float density[], float energy[], int NumElem); 

#ifdef __cplusplus 
} 
#endif 

CFE.c

void CFE(float density[], float energy[], int NumElem) 
{ 
    ... 

    float * dens; 
    dens = density; //pass pointer of array density[0] in SA.cpp to CFE.c 

    for(n=0; n<NumElem; n++) 
    { ... modify dens (e.g. DensityArray from SA.cpp) ... } 

    float * engy; 
    engy = energy; //pass pointer of array energy[0] in SA.cpp to CFE.c 

    for(n=0; n<NumElem; n++) 
    { ... modify engy (e.g. EnergyArray from SA.cpp) ... } 
} 

Suis-je un accès causant la mémoire illégale en essayant d'accéder aux éléments vectoriels de la partie C de mon programme? Y a-t-il un moyen sûr de permettre cela?

Toute aide serait très appréciée.

+0

Pouvez-vous poster le code complet à CFE()? C'est là que votre bug est. –

+0

@Raugnar Eh bien, après tout, nous n'avons jamais résolu votre problème. Est-il possible que vous posiez un exemple petit mais plus complet qui illustre ce qui ne va pas? –

Répondre

11

Si vous restez dans les limites du vecteur, ce que vous faites semble être OK.

Vous pouvez traiter un vecteur std :: exactement comme s'il s'agissait d'un tableau C en faisant ce que vous faites - en prenant l'adresse du premier élément.La norme C++ a été modifiée pour permettre spécifiquement ce type d'utilisation.

Vous ne trouvez pas une copie de C++ le rectificatif technique 2003 à l'heure actuelle, mais apparemment l'arbitre de section correspondante est 23.2.4,

+0

Wow. Je ne le savais pas. Voter! Pouvez-vous fournir un lien vers la section de la norme qui l'indique? Merci! –

+0

C'est dans la Corrigenda Technique - Je n'ai pas de copie sur cette machine mais j'essaierai d'en trouver une. –

+0

Le projet de norme (non officiel) peut être trouvé à ftp://ftp.research.att.com/dist/c++std/WP/CD2/. Voir 23.1.1 paragraphe 9, 23.1 paragraphe 7, 23.2.4 paragraphe 1, et 24.1.5 paragraphe 1. –

0

Vous ne pouvez pas faire cela. La classe de vecteur n'est pas la même qu'un tableau de type C.

Vous devez le convertir en un tableau C normal avant de le passer à la fonction CFE.

Editer: Apparemment, ma réponse est fausse. Vérifiez le message de Neil.

+0

... ou lui fournir des accès sécurisés. – plinth

+0

Il prend l'adresse du premier élément - c'est le même que le nom d'un tableau C. –

+0

I est le même que le nom d'un tableau C en effet. Mais je pense qu'il ne devrait pas compter sur la façon dont la mémoire est disposée à l'intérieur de la classe Vector. Cela pourrait changer. Un pari sûr sera converti en un tableau C normal. –

0

Le code que vous avez posté est correct. Pourvu que chaque accès à un élément de tableau à l'intérieur de CFE() soit dans les limites, vous ne devriez pas avoir d'erreur de segmentation. Essayez d'exécuter votre programme sous valgrind et voyez s'il signale quelque chose d'inhabituel.

1

Le code que vous avez publié semble être OK - vous devrez donner plus de détails si vous voulez que le problème soit débogué. En fait, si vous exécutez le programme dans un débogueur, il devrait être capable de vous dire exactement quelle ligne de code provoque l'exception (vous devrez peut-être regarder dans une pile d'appels), ou simplement parcourir le programme jusqu'à ce qu'il plante. Quant à la confusion sur le fait de savoir si le vecteur peut être traité comme un tableau C, il peut certainement obtenir l'adresse du premier élément (par exemple &vect[0]) - si le vecteur contient des éléments.

Le C++ 03 norme dit ceci au sujet vector<> à 23.2.4:

Les éléments d'un vecteur sont stockés jointive, ce qui signifie que si v est un vector<T, Allocator>T est un type autre que bool, il obéit à l'identité &v[n] == &v[0] + n pour tous 0 <= n < v.size()

Notez que cela n'a pas été explicitement mentionnée dans la norme C++ 98 (mais était encore l'intention).

Voir aussi l'article de Herb Sutter:

Notez que vector<bool> ne peut pas être traité comme un tableau C - un cas particulier puisque les éléments vector<bool> ne sont pas stockés comme bool.

+0

Je ne peux pas sembler le trouver dans le projet de norme C++ 98, mais voir mon commentaire sur le poste de Neil pour les sections pertinentes. –

+0

L'instruction explicite n'est pas dans la norme 98. Sans la déclaration explicite, une implémentation de vecteur pervers pourrait avoir les éléments non contigus ou inversés en mémoire et être toujours conforme. –

0

Quel est le contenu de CFE()? Pourquoi ne pas définir CFE() as; vide CFE (densité float *, float * énergie, int NumElem);

Vous n'avez donc pas besoin de vous amuser avec les moulages et de le faire; densité [i] = ... à l'intérieur de vos boucles?

+0

La déclaration de CFE() avec les paramètres de tableau est équivalente à ce que vous proposez (et la conversion ne doit pas encore entrer en jeu - l'indexation de tableau est définie en termes d'arithmétique de pointeur). Cependant, je pense toujours que c'est une bonne idée car elle déclare CFE() à ce qui se passe réellement de toute façon. –

Questions connexes