एक संरचना युक्त एच फ़ाइल संकलित करते समय त्रुटि त्रुटि

मेरे पास यह ProcessStasts.h फ़ाइल है जो दो अन्य .h फ़ाइलों में शामिल है।

#pragma once

#include 
#include 

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

MPI_Datatype MPI_Cust_ProcessStats_create()
{
   //set data to create new MPI data type
    MPI_Datatype MPI_Cust_ProcessStats;
    MPI_Datatype dataTypes[5] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_FLOAT};
    int blockLengths[5] = {1, 1, 1, 1, 1};
    MPI_Aint offsets[5];

    offsets[0] = (MPI_Aint) offsetof(ProcessStats, rank);
    offsets[1] = (MPI_Aint) offsetof(ProcessStats, itLeft);
    offsets[2] = (MPI_Aint) offsetof(ProcessStats, crtIt);
    offsets[3] = (MPI_Aint) offsetof(ProcessStats, processFlag);
    offsets[4] = (MPI_Aint) offsetof(ProcessStats, speed);

   //create new MPI type based on data from above
    MPI_Type_create_struct(5, blockLengths, offsets, dataTypes, &MPI_Cust_ProcessStats);
    MPI_Type_commit(&MPI_Cust_ProcessStats);

    return MPI_Cust_ProcessStats;
}

जब मैं संकलन करने का प्रयास करता हूं तो मुझे यह त्रुटि मिलती है: त्रुटि LNK2005: MPI_Cust_ProcessStats_create (शून्य) पहले ही परिभाषित । यदि मैं #include "ProcessStasts.h" पर टिप्पणी करता हूं निर्देश और प्रक्रियाओं में से एक से ProcessStats संरचना का उपयोग करने वाली रेखा, यह सही ढंग से संकलित करती है। मैंने ProcessStats में निर्भर सभी पंक्तियों पर टिप्पणी करने का प्रयास किया और केवल # शामिल "ProcessStasts.h" कथन छोड़ दिया और मुझे यह lnk त्रुटि मिल गई। गलत क्या है?

3
किसी त्रुटि के कारण, संरचना को और वर्र्स के साथ बदल दिया ... डेटाटाइप सरणी के समान [6]। धन्यवाद, जिसने मुझे कुछ ऐसा देखा जो मैंने बाद में एक बग के रूप में खोजा होगा।
जोड़ा लेखक codiac, स्रोत
MPI संरचना डेटाटाइप कन्स्ट्रक्टर 3 के लिए पहला तर्क क्यों है जब आपके पास struct में 5 फ़ील्ड हैं?
जोड़ा लेखक Hristo Iliev, स्रोत

2 उत्तर

आप इस तरह लिख सकते हैं: पहले ProcessStasts.h है

#pragma once

#include 
#include 

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

MPI_Datatype MPI_Cust_ProcessStats_create();

तो ProcessStasts.c है

#include "ProcessStats.h"
MPI_Datatype MPI_Cust_ProcessStats_create()
{
   //set data to create new MPI data type
    MPI_Datatype MPI_Cust_ProcessStats;
    MPI_Datatype dataTypes[6] = {MPI_INT, MPI_INT, MPI_INT, MPI_INT, MPI_FLOAT};
    int blockLengths[5] = {1, 1, 1, 1, 1};
    MPI_Aint offsets[5];

    offsets[0] = (MPI_Aint) offsetof(ProcessStats, rank);
    offsets[1] = (MPI_Aint) offsetof(ProcessStats, itLeft);
    offsets[2] = (MPI_Aint) offsetof(ProcessStats, crtIt);
    offsets[3] = (MPI_Aint) offsetof(ProcessStats, processFlag);
    offsets[4] = (MPI_Aint) offsetof(ProcessStats, speed);

   //create new MPI type based on data from above
    MPI_Type_create_struct(3, blockLengths, offsets, dataTypes, &MPI_Cust_ProcessStats);
    MPI_Type_commit(&MPI_Cust_ProcessStats);

    return MPI_Cust_ProcessStats;
}

फिर आप ProcessStasts.h को जितनी बार चाहें उतनी बार शामिल कर सकते हैं। एक सुझाव के रूप में, एक शीर्ष फ़ाइल में कार्यों को परिभाषित न करें।

4
जोड़ा
हाँ, जिसने समस्या हल की। हालांकि मुझे समझ में नहीं आता क्यों, क्योंकि #pragma एक बार है
जोड़ा लेखक codiac, स्रोत
#pragma एक बार जब आप एक स्रोत फ़ाइल संकलित करते हैं तो मदद की जाती है। लेकिन विभिन्न स्रोत फ़ाइल के लिए यह संकलन करते समय ऑपरेशन भी शामिल करेगा।
जोड़ा लेखक yanchong, स्रोत

#pragma once instructs the preprocessor not to include a header file twice. This is mostly used to prevent recursive inclusions and multiple indirect inclusions, e.g.:

#include  //a.h already includes b.h
#include 

bpr की शुरुआत में #pragma एक बार के बिना, इसकी सामग्री दो बार शामिल हो जाएगी और संभवतः कुछ प्रतीकों के पुनर्वितरण का कारण बन जाएगी।

आपके मामले में क्या होता है एक पूरी तरह से अलग मामला है। सी और सी ++ में डिफ़ॉल्ट कार्यों के बाहरी संबंध हैं। इसका अर्थ यह है कि यदि आपके पास foo() फ़ाइल bar.c में परिभाषित किया गया है और फिर आप ऑब्जेक्ट फ़ाइल bar.c को संकलित करते हैं <�कोड > bar.o , ऑब्जेक्ट फ़ाइल foo के नाम से एक वैश्विक प्रतीक निर्यात करती है (वास्तव में सी ++ ओवरलोडिंग का समर्थन करने के लिए नाम को सजाने के लिए), जिसे प्रतीक तक पहुंचा जा सकता है (जिसे संदर्भित किया जाता है) ) अन्य ऑब्जेक्ट फाइलों से। अब अगर फ़ाइल baz.c में किसी अन्य फ़ंक्शन की परिभाषा है foo() (जो C ++ के मामले में एक ही हस्ताक्षर है), ऑब्जेक्ट फ़ाइल baz। o foo के नाम से वैश्विक प्रतीक भी निर्यात करता है। निष्पादन योग्य फ़ाइल बनाने के लिए जब ऑब्जेक्ट फ़ाइलें एक साथ जुड़ती हैं, तो लिंकर प्रत्येक प्रतीक को एक अद्वितीय स्मृति पते पर हल करने का प्रयास करता है। लेकिन अब एक समस्या है: दो कोड foo हैं और दोनों के पास अलग-अलग पते हैं। लिंकर (आमतौर पर) एक मानसिक नहीं है, इसलिए यह आपको प्रतीक पुनर्वितरण के बारे में एक त्रुटि संदेश देता है और समाप्त करता है।

सी और सी ++ दोनों कार्यों के संबंध को नियंत्रित करने के लिए एक तंत्र प्रदान करते हैं। यदि आप static कीवर्ड जोड़ते हैं, तो फ़ंक्शन प्रतीक अब वैश्विक नहीं है और संकलन के समान इकाई को साझा करने वाले कोड के लिए केवल दिखाई देता है। इस तरह के कार्यों में स्थिर जुड़ाव है। यही कारण है कि हेडर फ़ाइलों में परिभाषित फ़ंक्शंस लगभग हमेशा स्थिर कीवर्ड के साथ आते हैं:

#pragma once

#include 
#include 

struct ProcessStats
{
    int rank,
    itLeft,
    crtIt,
    processFlag;
    float speed;
};

static MPI_Datatype MPI_Cust_ProcessStats_create()
{
    ...
}

अब MPI_Cust_ProcessStats_create() केवल स्रोत फ़ाइल में दिखाई दे रहा है जिसमें हेडर फ़ाइल शामिल है।

अनचाहे सलाह: एमपीआईआई एपीआई कॉल के लिए एमपीआई _ </कोड> उपसर्ग आरक्षित है। उपयोगकर्ता कार्यों के लिए इसका उपयोग करना एक खराब प्रोग्रामिंग अभ्यास है क्योंकि ऐसे उपकरण हैं जो इस तथ्य पर भरोसा करते हैं कि केवल एमपीआई कॉल MPI _ से शुरू होते हैं और भ्रमित हो सकते हैं।

2
जोड़ा
यह बेहतर जवाब है क्योंकि यह त्रुटि के स्रोत को बताता है; यह जुड़ाव के बारे में है। ध्यान दें कि फ़ंक्शन इनलाइन घोषित करना भी काम करेगा।
जोड़ा लेखक Ben Hymers, स्रोत
.cpp फ़ाइल में या स्थिर जोड़कर, क्यों (एक मोड बनाम अन्य लाभ कैसे बनाते हैं) के रूप में आप इस पर कैसे पहुंचेंगे?
जोड़ा लेखक codiac, स्रोत
मुझे stackoverflow पर MPI_Datatype बनाने का यह तरीका मिला। मैं इस फ़ंक्शन का उपयोग करके डेटाटाइप कैसे बना सकता हूं?
जोड़ा लेखक codiac, स्रोत
यह वरीयता का मामला है। यदि आप इसे एक अलग स्रोत फ़ाइल में डालते हैं, तो यह केवल एक बार संकलित होता है। यदि आप इसे हेडर में रखते हैं, तो इसे कई बार संकलित किया जाता है। यदि आप इसे हेडर फ़ाइल में रखते हैं और फ़ंक्शन के कोड में परिवर्तन करना है, तो आपको हेडर फ़ाइल को शामिल करने वाली प्रत्येक फ़ाइल को पुन: संकलित करना होगा। यदि यह एक अलग फ़ाइल में है, तो इसे केवल पुन: संकलित करना होगा।
जोड़ा लेखक Hristo Iliev, स्रोत
कुछ लोग हेडर फाइलों में छोटे कार्यों को रखना पसंद करते हैं क्योंकि इन्हें ऑप्टिमाइज़िंग कंपाइलर्स द्वारा रेखांकित किया जा सकता है। यदि फ़ंक्शन एक अलग अनुवाद इकाई में है, तो यह कठिन हो जाता है (लेकिन अंतर-प्रक्रियात्मक अनुकूलन जैसी चीज़ों के साथ असंभव नहीं है)।
जोड़ा लेखक Hristo Iliev, स्रोत