অনুপস্থিত # অন্তর্ভুক্ত পক্ষে রানটাইমের সময় প্রোগ্রামটি ভাঙ্গা সম্ভব?


31

#includeবিল্ডটি এখনও চলছে এমন কোনও ঘটনা রয়েছে যেখানে রানটাইমের সময় একটি অনুপস্থিত থাকলে সফটওয়্যারটি ভেঙে যায়?

অন্য কথায়, এটা কি সম্ভব?

#include "some/code.h"
complexLogic();
cleverAlgorithms();

এবং

complexLogic();
cleverAlgorithms();

উভয় সফলভাবে নির্মাণ করতে হবে, কিন্তু ভিন্ন আচরণ?


1
সম্ভবত আপনার অন্তর্ভুক্তের সাথে আপনি নিজের কোডটিকে পুনরায় সংজ্ঞায়িত কাঠামো আনতে পারেন যা ফাংশনগুলির প্রয়োগের দ্বারা ব্যবহৃত ব্যবস্থাগুলির চেয়ে আলাদা। এটি বাইনারি অসঙ্গতি হতে পারে। সংকলক এবং লিঙ্কার দ্বারা এই ধরনের পরিস্থিতি পরিচালনা করা যায় না।
আর্মাজেডেস্কু

11
এটি নিশ্চিতভাবে. কোনও শিরোনামে ম্যাক্রো সংজ্ঞায়িত করা বেশ সহজ যে এই শিরোলেখের পরে #includeডি কোড আসার পরে কোডটির অর্থ সম্পূর্ণভাবে পরিবর্তিত হয় ।
পিটার

4
আমি নিশ্চিত কোড গল্ফ এর ভিত্তিতে কমপক্ষে একটি চ্যালেঞ্জ করেছে।
চিহ্নিত করুন

6
আমি একটি নির্দিষ্ট বাস্তব-বিশ্বের উদাহরণটি উল্লেখ করতে চাই: মেমরি ফাঁস সনাক্তকরণের জন্য ভিএলডি গ্রন্থাগার । যখন কোনও প্রোগ্রাম ভিএলডি সক্রিয় সাথে বন্ধ হয়ে যায়, এটি কিছু আউটপুট চ্যানেলে সনাক্ত করা সমস্ত মেমরির ফাঁস মুদ্রণ করে। আপনি এটি ভিএলডি গ্রন্থাগারের সাথে সংযুক্ত করে #include <vld.h>এবং আপনার কোডের কৌশলগত অবস্থানে একটি একক লাইন রেখে কোনও প্রোগ্রামে এটি সংহত করেছেন । ভিএলডি শিরোনামটি সরানো বা যুক্ত করা প্রোগ্রামটি "ব্রেক" করে না, তবে এটি রানটাইমের আচরণকে উল্লেখযোগ্যভাবে প্রভাবিত করে। আমি দেখেছি ভিএলডি কোনও প্রোগ্রামকে ধীরে ধীরে ধীরে ধীরে কমিয়ে দেয় যাতে এটি অকেজো হয়ে যায়।
হালিবুর্টন

উত্তর:


40

হ্যাঁ, এটি পুরোপুরি সম্ভব। আমি নিশ্চিত যে এখানে প্রচুর উপায় রয়েছে তবে ধরুন অন্তর্ভুক্ত ফাইলটিতে একটি বৈশ্বিক পরিবর্তনশীল সংজ্ঞা রয়েছে যা একটি কনস্ট্রাক্টর বলে। প্রথম ক্ষেত্রে কনস্ট্রাক্টর মৃত্যুদন্ড কার্যকর করত এবং দ্বিতীয় ক্ষেত্রে তা করত না।

শিরোনাম ফাইলে একটি বৈশ্বিক পরিবর্তনশীল সংজ্ঞা স্থাপন করা দুর্বল স্টাইল, তবে এটি সম্ভব।


1
<iostream>স্ট্যান্ডার্ড লাইব্রেরিতে যথাযথভাবে এটি করে; যদি কোনও অনুবাদ ইউনিট অন্তর্ভুক্ত থাকে <iostream>তবে std::ios_base::Initপ্রোগ্রামের শুরুতে স্থির অবজেক্টটি নির্মিত হবে, চরিত্রের প্রবাহগুলি শুরু std::coutকরতে হবে ইত্যাদি, অন্যথায় এটি হবে না।
এ্যাক্যাটমুর

33

হ্যাঁ, এটা সম্ভব

এর সাথে সম্পর্কিত সমস্ত কিছুই #includeসংকলন সময়ে ঘটে। তবে সংকলনের সময় বিষয়গুলি রানটাইমের সময় অবশ্যই আচরণ পরিবর্তন করতে পারে:

some/code.h:

#define FOO
int foo(int a) { return 1; }

তারপর

#include <iostream>
int foo(float a) { return 2; }

#include "some/code.h"  // Remove that line

int main() {
  std::cout << foo(1) << std::endl;
  #ifdef FOO
    std::cout << "FOO" std::endl;
  #endif
}

এর সাথে #include, ওভারলোড রেজোলিউশনটি আরও উপযুক্ত foo(int)এবং এর 1পরিবর্তে প্রিন্টগুলি সন্ধান করে 2। এছাড়াও, যেহেতু FOOসংজ্ঞায়িত করা হয়, এটি অতিরিক্ত মুদ্রণ করে FOO

এটি কেবল দুটি (সম্পর্কিত নয়) উদাহরণ যা আমার মনে সঙ্গে সঙ্গেই এসেছিল এবং আমি নিশ্চিত যে আরও অনেক কিছু রয়েছে are


14

কেবল তুচ্ছ ঘটনাটি দেখানোর জন্য, পূর্বপরিবর্তক নির্দেশিকা:

// main.cpp
#include <iostream>
#include "trouble.h" // comment this out to change behavior

bool doACheck(); // always returns true

int main()
{
    if (doACheck())
        std::cout << "Normal!" << std::endl;
    else
        std::cout << "BAD!" << std::endl;
}

এবং তারপর

// trouble.h
#define doACheck(...) false

এটি প্যাথলজিকাল, সম্ভবত, তবে আমার একটি সম্পর্কিত ঘটনা ঘটেছে:

#include <algorithm>
#include <windows.h> // comment this out to change behavior

using namespace std;

double doThings()
{
    return max(f(), g());
}

নিরীহ দেখাচ্ছে। ফোন করার চেষ্টা করে std::max। যাইহোক, উইন্ডোজ। হ'ল সর্বাধিক সংজ্ঞা দেয়

#define max(a, b)  (((a) > (b)) ? (a) : (b))

এটি যদি হয় std::maxতবে এটি একটি সাধারণ ফাংশন কল যা একবার চ () এবং জি () একবার মূল্যায়ন করে। তবে সেখানে উইন্ডোজ। দিয়ে, এটি এখন চ () বা জি () দুবার মূল্যায়ন করে: একবার তুলনার সময় এবং একবার ফেরতের মান পেতে। যদি f () বা g () আদর্শহীন না হয়ে থাকে তবে এটি সমস্যার কারণ হতে পারে। উদাহরণস্বরূপ, যদি তাদের মধ্যে একটির এমন কাউন্টার হয়ে যায় যা প্রতিবারই একটি পৃথক নম্বর ফেরত দেয় ...


উইন্ডো সর্বাধিক কার্যকারিতা কল করার জন্য +1, বাস্তবায়নের মন্দ এবং সর্বত্র বহনযোগ্যতার জন্য নিষেধ অন্তর্ভুক্ত করার প্রকৃত বিশ্ব উদাহরণ।
স্কট এম

3
OTOH, আপনি যদি পরিত্রাণ পান using namespace std;এবং ব্যবহার করেন std::max(f(),g());তবে সংকলক সমস্যাটি ধরবে (একটি অস্পষ্ট বার্তা সহ, তবে কমপক্ষে কল সাইটের দিকে নির্দেশ করবে)।
রুসলান

@ রাস্লান ওহ, হ্যাঁ যদি সুযোগ দেওয়া হয় তবে এটি সেরা পরিকল্পনা। তবে কখনও কখনও একজন লিগ্যাসি কোড নিয়ে কাজ করছেন ... (কোনও কথা নয় ... তেতো নয়, মোটেও তিক্ত নয়!)
কর্ট অ্যাম্মোন

4

কোনও টেম্পলেট বিশেষায়নের অনুপস্থিত হওয়া সম্ভব।

// header1.h:

template<class T>
void algorithm(std::vector<T> &ts) {
    // clever algorithm (sorting, for example)
}

class thingy {
    // stuff
};

// header2.h

template<>
void algorithm(std::vector<thingy> &ts) {
    // different clever algorithm
}

// main.cpp

#include <vector>
#include "header1.h"
//#include "header2.h"

int main() {
    std::vector<thingy> thingies;
    algorithm(thingies);
}

4

বাইনারি অসঙ্গতি, কোনও সদস্য অ্যাক্সেস করা বা আরও খারাপ, ভুল শ্রেণির ফাংশনকে ডেকে আনা:

#pragma once

//include1.h:
#ifndef classw
#define classw

class class_w
{
    public: int a, b;
};

#endif

একটি ফাংশন এটি ব্যবহার করে এবং এটি ঠিক আছে:

//functions.cpp
#include <include1.h>
void smartFunction(class_w& x){x.b = 2;}

ক্লাসের অন্য একটি সংস্করণ নিয়ে আসা:

#pragma once

//include2.h:
#ifndef classw
#define classw

class class_w
{
public: int a;
};

#endif

প্রধানত ফাংশন ব্যবহার করে, দ্বিতীয় সংজ্ঞা শ্রেণীর সংজ্ঞা পরিবর্তন করে। এটি বাইনারি অসম্পূর্ণতার দিকে নিয়ে যায় এবং রানটাইমে কেবল ক্র্যাশ হয়। এবং মেইন.পি.পি. এর মধ্যে প্রথমটি অন্তর্ভুক্ত করে সমস্যাটি সমাধান করুন:

//main.cpp

#include <include2.h> //<-- Remove this to fix the crash
#include <include1.h>

void smartFunction(class_w& x);
int main()
{
    class_w w;
    smartFunction(w);
    return 0;
}

কোনও রূপই একটি সংকলন বা লিঙ্ক সময়ের ত্রুটি তৈরি করে না।

তদ্বিপরীত পরিস্থিতি, একটি অন্তর্ভুক্ত করা ক্রাশটিকে সংশোধন করে:

//main.cpp
//#include <include1.h>  //<-- Add this include to fix the crash
#include <include2.h>
...

প্রোগ্রামের পুরানো সংস্করণে বাগ ফিক্স করার সময়, বা একটি বাহ্যিক লাইব্রেরি / dll / শেয়ারকৃত অবজেক্ট ব্যবহার করার সময় এই পরিস্থিতি আরও বেশি জটিল। যে কারণে কখনও কখনও বাইনারি পশ্চাদপদ সামঞ্জস্যের নিয়মগুলি মেনে চলতে হবে।


দ্বিতীয় হেডার ইফেনডেফের কারণে অন্তর্ভুক্ত হবে না। অন্যথায় এটি সংকলন করবে না (শ্রেণি পুনঃনির্ধারণ অনুমোদিত নয়)।
ইগোর আর

@IgorR। মনযোগী হও. দ্বিতীয় শিরোনাম (অন্তর্ভুক্ত 1 এইচ) কেবলমাত্র প্রথম উত্স কোডে অন্তর্ভুক্ত। এটি বাইনারি অসঙ্গতি বাড়ে। কোডটির সঠিক উদ্দেশ্য, ইলাস্ট্রেট করা যাতে কোনও অন্তর্ভুক্ত কীভাবে রানটাইমের সময় ক্রাশ হতে পারে।
আর্মাজেডেস্কু

1
@IgorR। এটি অত্যন্ত সরল কোড, যা এ জাতীয় পরিস্থিতি চিত্রিত করে। তবে বাস্তব জীবনের পরিস্থিতি আরও জটিল জটিল সাবলেট হতে পারে। পুরো প্যাকেজটি পুনরায় ইনস্টল না করে কিছু প্রোগ্রাম প্যাচ করার চেষ্টা করুন। এটি সেই সাধারণ পরিস্থিতি যেখানে পশ্চাদপটে বাইনারি সামঞ্জস্যের বিধি কঠোরভাবে অনুসরণ করতে হবে। অন্যথায় প্যাচিং একটি অসম্ভব কাজ।
আরমাজেডেস্কু

আমি "প্রথম উত্স কোড" কী তা নিশ্চিত নই তবে আপনি যদি বোঝেন যে 2 টি অনুবাদ ইউনিটে একটি শ্রেণীর 2 টি পৃথক সংজ্ঞা থাকে তবে এটি ওডিআর লঙ্ঘন, অর্থাৎ অপরিজ্ঞাত আচরণ।
ইগোর আর।

1
যে অনির্ধারিত আচরণ যেমন সি ++ স্ট্যান্ডার্ড দ্বারা বর্ণনা। এফডাব্লুআইডাব্লু, অবশ্যই এইভাবে কোনও ইউবি তৈরি করা সম্ভব ...
আইগোর আর

3

আমি উল্লেখ করতে চাই যে সিটিতেও সমস্যাটি রয়েছে

আপনি কম্পাইলারকে বলতে পারেন কোনও ফাংশন কিছু কলিং কনভেনশন ব্যবহার করে। আপনি যদি না করেন, সংকলকটিকে অনুমান করতে হবে যে এটি সি ++ এর বিপরীতে ডিফল্ট ব্যবহার করে, যেখানে সংকলক এটি সংকলন করতে অস্বীকার করতে পারে।

উদাহরণ স্বরূপ,

main.c

int main(void) {
  foo(1.0f);
  return 1;
}

foo.c

#include <stdio.h>

void foo(float x) {
  printf("%g\n", x);
}

X86-64 এর লিনাক্সে, আমার আউটপুট

0

আপনি যদি এখানে প্রোটোটাইপ বাদ দেন তবে সংকলকটি ধরে নিয়েছে

int foo(); // Has different meaning in C++

এবং অনির্ধারিত যুক্তি তালিকার কনভেনশনের প্রয়োজন যা পাস floatকরার doubleজন্য রূপান্তর করা উচিত । যদিও আমি দিয়েছি 1.0f, সংকলক এটি এটিকে 1.0dপাস করার জন্য রূপান্তর করে foo। এবং সিস্টেম ভি অ্যাপ্লিকেশন বাইনারি ইন্টারফেস AMD64 আর্কিটেকচার প্রসেসর পরিপূরক অনুসারে, double64 টির কমপক্ষে উল্লেখযোগ্য বিটগুলিতে পাস হয় xmm0। তবে fooএকটি ভাসমান প্রত্যাশা করে, এবং এটি 32 টি সর্বনিম্ন উল্লেখযোগ্য বিট থেকে এটি পড়ে xmm0এবং 0 পায় 0

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.