Tuesday, 2 May 2017

Header Guards in marathi

हेडर गार्ड वर बोलूया काही तरी .. 


हेडर गार्ड बद्दल सुरवात करण्या आधी आपण थोड डुप्लिकेट डेफिनिशन चे प्रॉब्लेम बघूया. 

डुप्लिकेट डेफिनिशन चे अडथळे :

C/C++ मध्ये एखाद्या identifier ला एक आणि एकच definition असते, त्यामुळे जर कुणी प्रोग्रॅम मध्ये एखादा variable identifier एक पेक्षा जास्त वेळा वापरल्यास कंपायलर लगेच बोंबलतो. याच प्रमाणे जर एखाद्या प्रोग्राम मध्ये एकाच नावाची function एक पेक्षा वेळ define केलेली असल्यास सुद्धा कंपायलर 


int main()
{
    int x; // this is a definition for identifier x
    int x; // compile error: duplicate definition
 
    return 0;
}

याच प्रमाणे जर एखाद्या प्रोग्राम मध्ये एकाच नावाच function एक पेक्षा अनेक वेळ define केल असल्यास सुद्धा कंपायलर लगेच बोंबलतो . उदा :

#include < iostream >

int foo(void){
  return 5;
}

int foo(void){   // कंपायलर लगेच बोंबलेल डुप्लिकेट आहे म्हणून 

  return 5;
}

int main()
{
    std::cout << foo() << endl; 
    return 0;
}

आता कंपायलर बोंबलल्यावर आपण एक function काढून टाकला तर आपला प्रॉब्लेम सुटेल परंतु हेडर फाईल जर एक पेक्षा जास्त वेळ इम्पोर्ट झाल्यास आपल्यावर हि वेळ येईल आणि आपण रडत बसू , मी तर हेडर फाईल एकदाच तर टाकली .... तरी हे function परत आलं कुठून ...कटकट ... हि कटकट तेव्हा येईल जर तीच हेडर फाईल अजून कुठल्या आतमधल्या हेडर फाईल नि स्वतः #include टाकून ठेवली असेल (बरेच दा असच होत , दुसऱ्यांवर अवलंबून राहण्यापेक्षा 'अनेक' हेडर फाईल - 'अनेक' हेडर फाईलला स्वतःच include करून घेतात )अन हे आपल्याला माहित पण नसेल (माहित होईल जर प्रत्येक फाईल आतमध्ये काय काय include करत असेल याचा शोध घेतला तरच.... जो आपण कधीही घेत नाही). 

खालील उदाहरण बघा :

समजा आपल्याकडे maths.h नावाची हेडर फाईल आहे आणि त्यात एक function डेफिनेशन सकट आहे (हेडर फाईल मध्ये डेफिनेशन सकट functions असता काम नये इथे फक्त उदाहरण घेण्यासाठीच लिहिलेलं आहे कृपया असं लिहू नका ) , हि  फाईल geometry.h हेडर फाईल मध्ये सुद्धा इंपोर्टेड आहे आणि main.cpp मध्ये सुद्धा आहे. 

१. math.h:

int getSquareSides()
{
    return 4;
}


२. geometry.h:
#include "maths.h"

३. main.cpp:


#include "maths.h"
#include "geometry.h"

int main(void){
   return 0;
}

या प्रोग्रॅम कडे बघितलं तर काही हि चुकीचं दिसत नाही , परंतु हा प्रोग्रॅम compile होणार नाही. कारण शोधायला गेलं तर एकच सापडेल maths.h मध्ये असलेलं function definition. इथे main.cpp मध्ये पहिल्यांदा "maths.h" इम्पोर्ट झालेलं आहे म्हणजेच getSquareSides() हे function इम्पोर्ट झालं आणि परत geometry.h मध्ये सुद्धा maths.h असल्यामुळे परत getSquareSides() हे function पुन्हा इम्पोर्ट झालं. आता कोड बघितला तर असा दिसेल. 

main.cpp:

int getSquareSides()  //#include "maths.h" मुळे include झालेला 
{
    return 4;
}

int getSquareSides() //#include "geometry.h" मुळे include झालेला 
{
    return 4;
}

int main(void){
   return 0;
}

डुप्लिकेट definition मुळे हा प्रोग्रॅम compile होणार नाही. प्रत्येक हेडर फाईल स्वतंत्ररित्या एकदम व्यवस्थित आहे बरोबर आहे , परंतु आपण main.cpp मध्ये दोन्ही फाईल्स वापरल्यात आणि आपण असे गृहीत धरू कि आपल्याला हे माहित नाही कि geometry.h च्या आत मध्ये maths.h इम्पोर्ट केलं आहे. अशा वेळी आपण डुप्लिकेट definition च्या कचाट्यात सापडणारच. तर मग प्रश्न पडतो कि हा अडथळा सोडवायचा कसा ?

हे सुद्धा लक्षात असुद्या कि नुसतं variables असो कि functions असो किंवा कोणतीही डुप्लिकेट definition असो , असा प्रॉब्लेम येणारच. हा प्रॉब्लेम सोडविण्यासाठीच हेडर गार्ड आहे. 

Header Guards :

हेडर गार्डस हे conditional compilation directive आहे (conditional compilation म्हणजे काय याबद्दल आपण हेडर फाईल्स वर बोलूया काही तरी मध्ये सविस्तर बघितलेलं आहे). याला खालील फॉर्म मध्ये लिहता येत. 


#ifndef SOME_UNIQUE_NAME_HERE
#define SOME_UNIQUE_NAME_HERE

//तुमची declarations आणि definitions 


#endif

जेव्हा अशी हेडर फाईल include होईल तेव्हा प्रथम हे चेक केल्या जाईल कि SOME_UNIQUE_NAME_HERE  हे अगोदर कुणी define तर नाही ना केलं ? जर नसेल केलं तर आणि तरच #define SOME_UNIQUE_NAME_HERE आणि #endif च्या मधले content कॉपी केल्या जाईल. अगोदरच कुणीतरी include केले असेल तर पूर्ण हेडरफाईलच ignore केल्या जाईल. त्यामुळे डुप्लिकेट इम्पोर्ट होणारच नाही, म्हणून आपल्या प्रत्येक फाईल मध्ये हेडर गार्ड असायला पाहिजे. मग नाव काय द्यायचं ? काही भलतं सलत नाव देत बसण्यापेक्षा जे हेडर फाईल च नाव आहे तेच हेडर गार्ड च नाव कॅपिटल अक्षरात द्या जास्त शब्द असतील तर अंडरस्कोर वापरून जोडा आणि शेवटी _H लावा. उदा आपण आपली maths.h आणि geometry.h फाईल हेडर गार्ड वापरून तयार करूया. तर ती अशी दिसेल. 

१. math.h:
#ifndef MATHS_H
#define MATHS_H

int getSquareSides()
{
    return 4;
}
#endif  /*MATHS_H*/

२. geometry.h:
#ifndef GEOMETRY_H
#define GEOMETRY_H

#include "maths.h"

#endif  /*GEOMETRY_H*/

३. main.cpp:


#include "maths.h"    
#include "geometry.h" 

int main(void){
   return 0;
}

standard library सुद्धा हेडर गार्ड वापरतात जर तुम्ही iostream हेडर फाईल ला Visual Studio मध्ये बघाल तर खालील प्रमाणे दिसेल. 




हेडर गार्ड एक हेडर फाईल हि  वेग वेगळ्या source फाईल मध्ये इम्पोर्ट होणार नाही याला काही हि प्रतिबंध करू शकत नाही. 
गार्ड केलेली हेडर फाईल हि एका source फाईल मध्ये एक पेक्षा जास्त वेळ इम्पोर्ट होणार नाही याची खात्री हेडर गार्ड देते. हेडर गार्ड च designच तस असल्यामुळे ते एक आणि एकच source फाईल वर होईल परंतु दुसऱ्याही source फाईल न include केलेली असल्यास्त ती हेडर फाईल त्या source फाईल मध्ये सुद्धा include होईल. असं झाल्यास आपण अजून एका कचाट्यात सापडू .उदा :
१.square.h:
#ifndef SQUARE_H
#define SQUARE_H

int getSquareSides()
{
    return 4;
}

int getSquarePerimeter (int getSide);

#endif  /*SQUARE_H*/

२. square.cpp:
#include "square.h"    // इथे एकदा include झाली 

int getSquarePerimeter(int getSide){
   return getSide* getSquareSides();
}

३. main.cpp:
#include < iostream >
#include "square.h"   // इथे पुन्हा एकदा include झाली 

int main(void){
   std::cout << "a square has " << getSquareSides() << " sides" << std::endl;
   std::cout << "a square of length 5 has perimeter length " 
             << getSquarePerimeter(5) <<std::endl;
   return 0;
}

इथे square.h फाईल मध्ये जरी हेडर गार्ड असलं तरी त्यातले कन्टेन्ट एकदा square.cpp आणि एकदा main.cpp मध्ये कॉपी झाल. हे असं का झालं ते जरा खोलात जाऊन बघूया. 

जेव्हा square.h हेडर फाईल square.cpp फाईल मधून include झाली तेव्हा square.cpp फाईल चा स्कोप संपे पर्यंतच SQUARE_H defined राहील. त्यामुळे square.h फाईल हि फक्त square.cpp source फाईल मध्ये परत include होणार नाही. जसा square.cpp फाईल संपेल SQUARE_H सुद्धा not defined होईल , म्हणजेच आपण असं म्हणू शकतो कि जेव्हा प्रिप्रोसेसर main.cpp मध्ये रन होईल तेव्हा SQUARE_H हा main.cpp मध्ये सुरवातीला defined नाही होत. 

शेवटी getSquareSides() नावाचं function हे दोन्ही ठिकाणी येईल म्हणजेच square.cpp आणि main.cpp सुद्धा . प्रोग्रॅम तर compile होईल परंतु लिंकर ओरडेल कि getSquareSides() function जास्त वेळ आलं आहे म्हणून. 

हा अडथळा पार पडायला बरेच मार्ग आहे पण त्यातला सोपा म्हणजे हेडर फाईल मध्ये फक्त declaration ठेवा आणि कोणत्याही एका cpp फाईल मध्ये definition/implementation लिहा. 

१.square.h:
#ifndef SQUARE_H
#define SQUARE_H

int getSquareSides();

int getSquarePerimeter (int getSide);

#endif  /*SQUARE_H*/

२. square.cpp:
#include "square.h"    // इथे एकदा include झाली आणि इथे च इम्पलेमेंटेशन केलं 
int getSquareSides()
{
    return 4;
}

int getSquarePerimeter(int getSide){ return getSide* getSquareSides(); }

३. main.cpp:
#include < iostream >
#include "square.h"   // इथे पुन्हा एकदा include झालीतरी प्रॉब्लेम नाही येणार कारण डेफिनिशन एकच आहे  

int main(void){
   std::cout << "a square has " << getSquareSides() << " sides" << std::endl;
   std::cout << "a square of length 5 has perimeter length " 
             << getSquarePerimeter(5) <<std::endl;
   return 0;
}

आता जरी हेडर फाईल दोनदा अली असली तरी डेफिनिशन एकच असल्यामुळे लिंकर आनंदी आहे त्यामुळे आपला अडथळा मिटला . 

#pragma once
बरीच कंपायलर हेडर गार्ड च्या ऐवजी/ किंवा अल्टरनेटीव्ह म्हणून #pragma  directive सपोर्ट करतात.

#pragma once






#pragma once हेडर गार्ड सारखीच काम करतात , फरक एकच कि इथे एकाच लाईन मध्ये काम होऊन जाते. 

iostream मध्ये सुद्धा याचा वापर केलेला आहे आधीच्या image मध्ये बघा. सांगायचं झालं तर #pragma once हे  C++ कडून official नाही आहे. आणि सर्वच कंपायलर सपोर्ट करतील असते नाही (आजची बरीच सपोर्ट करतात वरील image मध्ये दाखवल्याप्रमाणे ) जुने प्रोग्रॅम सुद्धा चालावी म्हणून ( backward compatibility) असावी म्हणून आपण हेडर गार्ड चा वापर करावा 


पुनरावलोकन : 


Duplicate definition टाळण्यासाठी हेडर गार्ड तयार करण्यात आले परंतु हेडर गार्ड फक्त एकाच फाईल मध्ये एखादी हेडर फाईल एक पेक्षा जास्त वेळ येणार नाही याची खात्री देते , दुसऱ्या source फाईल मध्ये येणार नाही याची नाही . 

No comments:

Post a Comment