উনল - C এবং C++ উভয় ক্ষেত্রে বৈধ যে কোডটি প্রতিটি ভাষায় সংকলিত হওয়ার সময় বিভিন্ন আচরণ তৈরি করতে পারে?




সি++ বই (13)

C ++ বনাম C90 এর জন্য, প্রয়োগের সংজ্ঞায়িত না করা বিভিন্ন আচরণ পেতে অন্তত একটি উপায় আছে। C90 একক লাইন মন্তব্য নেই। সামান্য যত্ন সহ, আমরা C90 এবং C ++ এ পুরোপুরি ভিন্ন ফলাফল সহ একটি অভিব্যক্তি তৈরি করতে ব্যবহার করতে পারি।

int a = 10 //* comment */ 2 
        + 3;

সি ++ এ, // থেকে লাইনের শেষে সবকিছুই একটি মন্তব্য, তাই এটি এইভাবে কাজ করে:

int a = 10 + 3;

যেহেতু C90 এর একক লাইন মন্তব্য নেই, কেবলমাত্র /* comment */ একটি মন্তব্য। প্রথম / এবং 2 উভয়ই প্রাথমিকভাবে শুরু হয়, তাই এটি আসে:

int a = 10 / 2 + 3;

সুতরাং, একটি সঠিক সি ++ কম্পাইলার 13 দেবে, কিন্তু একটি কঠোরভাবে সঠিক C90 কম্পাইলার 8. অবশ্যই, আমি এখানে অবাধ সংখ্যাগুলি বাছাই করেছি - আপনি উপযুক্ত দেখতে অন্যান্য নম্বরগুলি ব্যবহার করতে পারেন।

সি এবং সি ++গুলিতে অনেক পার্থক্য রয়েছে এবং সমস্ত বৈধ সি কোড বৈধ সি ++ কোড নয়।
("বৈধ" অনুসারে আমি নির্ধারিত আচরণের সাথে মানক কোড, অর্থাৎ বাস্তবায়ন-নির্দিষ্ট / অনির্ধারিত / ইত্যাদি নয়।)

সি এবং সি ++ উভয় ক্ষেত্রে বৈধ কোডের একটি টুকরা প্রতিটি ভাষাতে একটি আদর্শ কম্পাইলারের সাথে সংকলিত হলে বিভিন্ন আচরণ তৈরি করবে কি এমন কোন দৃশ্যকল্প আছে?

এটি একটি যুক্তিসঙ্গত / দরকারী তুলনা (আমি কার্যকরীভাবে কিছু শিখতে চেষ্টা করছি, প্রশ্নে সুস্পষ্ট ত্রুটি খুঁজে বের করার চেষ্টা না করা), আসুন ধরুন:

  • কিছুই #ifdef __cplusplus সম্পর্কিত নয় (যার অর্থ #ifdef __cplusplus , pragmas, ইত্যাদি সহ কোন হ্যাক নেই)
  • বাস্তবায়ন-সংজ্ঞায়িত কিছু উভয় ভাষা একই হয় (যেমন সংখ্যাসূচক সীমা, ইত্যাদি)
  • আমরা প্রতিটি মানের যথাযথ সাম্প্রতিক সংস্করণের তুলনা করছি (উদাহরণস্বরূপ, সি ++ 98 এবং C90 বা পরে)
    যদি সংস্করণগুলি গুরুত্বপূর্ণ হয় তবে অনুগ্রহ করে উল্লেখ করুন যে প্রতিটি সংস্করণগুলি কীভাবে ভিন্ন আচরণ করে।

C এবং C ++ গ্লোবাল নামস্থানগুলির মধ্যে পার্থক্যটি ভুলবেন না। ধরুন আপনার একটি foo.cpp আছে

#include <cstdio>

void foo(int r)
{
  printf("I am C++\n");
}

এবং একটি foo2.c

#include <stdio.h>

void foo(int r)
{
  printf("I am C\n");
}

এখন অনুমান করুন আপনার একটি main.c এবং main.cpp রয়েছে যা উভয়ই এটির মত দেখাচ্ছে:

extern void foo(int);

int main(void)
{
  foo(1);
  return 0;
}

সি ++ হিসাবে সংকলিত হলে, এটি সি ++ গ্লোবাল নেমস্পেসে প্রতীক ব্যবহার করবে; সি তে এটি সি ব্যবহার করবে:

$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test 
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test 
I am C

আরেকটি sizeof ফাঁদ: বুলিয়ান এক্সপ্রেশন।

#include <stdio.h>
int main() {
    printf("%d\n", (int)sizeof !0);
}

এটি সি-তে sizeof(int) সমান, কারণ এক্সপ্রেশনটি টাইপ int , তবে সাধারণত C ++ তে (যদিও এটি প্রয়োজন হয় না)। অনুশীলনে তারা প্রায় সবসময় ভিন্ন।


আরেকটি উদাহরণ যা আমি এখনো উল্লেখ করিনি, এটি একটি প্রপ্রপ্রাক্সার পার্থক্যকে হাইলাইট করে:

#include <stdio.h>
int main()
{
#if true
    printf("true!\n");
#else
    printf("false!\n");
#endif
    return 0;
}

এই সিটিতে "মিথ্যা" এবং সি ++ তে "সত্য" মুদ্রণ করে - C তে, কোন অনির্ধারিত ম্যাক্রো 0 এর মূল্যায়ন করে। C ++ তে, 1 টি ব্যতিক্রম রয়েছে: "সত্য" 1 এর মূল্যায়ন করে।


এই সি এবং সি ++ মধ্যে lvalues ​​এবং rvalues ​​উদ্বেগ।

সি প্রোগ্রামিং ভাষাতে, প্রাক-বৃদ্ধি এবং পোস্ট-ইনক্রিমেন্ট অপারেটর উভয় পরিমাণে রেভালিউস ফেরত দেয়। এর মানে হল যে তারা = অ্যাসাইনমেন্ট অপারেটরের বাম পাশে থাকতে পারে না। এই বিবৃতি উভয় সি একটি কম্পাইলার ত্রুটি দিতে হবে:

int a = 5;
a++ = 2;  /* error: lvalue required as left operand of assignment */
++a = 2;  /* error: lvalue required as left operand of assignment */

সি ++ এর মধ্যে, প্রি-ইনক্রিমেন্ট অপারেটর একটি তরল প্রদান করে , যখন পোস্ট ইনক্রিমেন্ট অপারেটর একটি রেভালু প্রদান করে। এর মানে হল প্রাক-বৃদ্ধি অপারেটরের সাথে একটি এক্সপ্রেশন = অ্যাসাইনমেন্ট অপারেটরের বামদিকে স্থাপন করা যেতে পারে!

int a = 5;
a++ = 2;  // error: lvalue required as left operand of assignment
++a = 2;  // No error: a gets assigned to 2!

এখন কেন এমন হয়? পোস্ট বৃদ্ধি বৃদ্ধি পরিবর্তনশীল, এবং এটি পরিবর্তনশীল ঘটেছে আগে এটি পরিবর্তনশীল ফেরত। এই আসলে শুধু একটি rvalue হয়। পরিবর্তনশীল একটি প্রাক্তন মান একটি অস্থায়ী হিসাবে একটি নিবন্ধে অনুলিপি করা হয়, এবং তারপর একটি বৃদ্ধি হয়। কিন্তু একটি প্রাক্তন মানটি অভিব্যক্তি দ্বারা ফেরত পাঠানো হয়, এটি একটি র্যালুউ। এটি আর পরিবর্তনশীল বর্তমান কন্টেন্ট প্রতিনিধিত্ব করে না।

প্রি-ইনক্রিমেন্ট প্রথম পরিবর্তনশীল বৃদ্ধি করে এবং তারপরে পরিবর্তনশীল হওয়ার পরে এটি পরিবর্তনশীল ফেরত দেয়। এই ক্ষেত্রে, আমরা একটি অস্থায়ী নিবন্ধন মধ্যে পরিবর্তনশীল পুরানো মান সঞ্চয় করার প্রয়োজন হয় না। এটি বৃদ্ধি পেয়ে যাওয়ার পরে আমরা কেবল পরিবর্তনশীলের নতুন মান পুনরুদ্ধার করি। সুতরাং প্রাক-বৃদ্ধি একটি lvalue প্রদান করে, এটি পরিবর্তনশীল নিজেই প্রদান করে। আমরা অন্য কিছুতে এই তরঙ্গ বরাদ্দ ব্যবহার করতে পারেন, এটি নিম্নোক্ত বিবৃতি মত। এটি rvalue মধ্যে lvalue একটি অন্তর্নিহিত রূপান্তর।

int x = a;
int x = ++a;

যেহেতু প্রি-ইনক্রিমেন্টটি একটি লভ্যুইটি ফেরত দেয়, তাই আমরা এটিতে কিছু নির্দিষ্ট করতে পারি। নিম্নলিখিত দুটি বিবৃতি অভিন্ন। দ্বিতীয় অ্যাসাইনমেন্টে, প্রথমটি বৃদ্ধি হয়, তার নতুন মান 2 এর সাথে ওভাররাইট করা হয়।

int a;
a = 2;
++a = 2;  // Valid in C++.

একটি পুরানো চিনাবাদাম যা সি কম্পাইলারের উপর নির্ভর করে, সি ++ শেষ-লাইন মন্তব্যগুলি স্বীকৃতি দেয় না ...

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...

খালি কাঠামোগুলির আকার 0 C এবং C ++ এর মধ্যে 1:

#include <stdio.h>

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}

নিম্নলিখিতগুলি সি এবং সি ++ এ বৈধ, সি (C) এবং সি ++ এর মধ্যে (সম্ভবতঃ) বিভিন্ন মানের মধ্যে চলছে:

int i = sizeof('a');

পার্থক্য ব্যাখ্যা করার জন্য C / C ++ তে চরিত্রের আকার ('a') দেখুন

এই নিবন্ধটি থেকে আরেকটি:

#include <stdio.h>

int  sz = 80;

int main(void)
{
    struct sz { char c; };

    int val = sizeof(sz);      // sizeof(int) in C,
                               // sizeof(struct sz) in C++
    printf("%d\n", val);
    return 0;
}

সি ++ স্ট্যান্ডার্ড দ্বারা তালিকাভুক্ত অন্য একটি:

#include <stdio.h>

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}

সি ডিফল্ট থেকে বাইরের ক্ষেত্রে ইনলাইন ফাংশন যেখানে সি ++ তে নেই।

নিম্নলিখিত দুটি ফাইলগুলি একত্রিত করে GNU C এর ক্ষেত্রে "আমি ইনলাইন" মুদ্রণ করব কিন্তু সি ++ এর জন্য কিছুই না।

ফাইল 1

#include <stdio.h>

struct fun{};

int main()
{
    fun();  // In C, this calls the inline function from file 2 where as in C++
            // this would create a variable of struct fun
    return 0;
}

ফাইল 2

#include <stdio.h>
inline void fun(void)
{
    printf("I am inline\n");
} 

এছাড়াও, সি ++ নিবিড়ভাবে static হিসাবে কোনও বিশ্বব্যাপী static extern না যতক্ষন না এটি স্পষ্টভাবে extern ঘোষণা করা হয়, যা C এর বিপরীতে extern ডিফল্ট।


#include <stdio.h>

int main(void)
{
    printf("%d\n", (int)sizeof('a'));
    return 0;
}

সি-তে, এই প্রিন্টগুলি যা sizeof(int) এর মান বর্তমান সিস্টেমে থাকে, যা আজ সাধারণত বেশিরভাগ সিস্টেমে 4 হয়।

সি ++ এ, এটি 1 টি মুদ্রণ করতে হবে।


#include <stdio.h>

struct A {
    double a[32];
};

int main() {
    struct B {
        struct A {
            short a, b;
        } a;
    };
    printf("%d\n", sizeof(struct A));
    return 0;
}

এই প্রোগ্রামটি একটি সি ++ কম্পাইলার এবং 4 সি কম্পাইলার ব্যবহার করে কম্পাইল করার সময় কম্পাইল করার সময় 128 ( 32 * sizeof(double) ) মুদ্রণ করে।

এই কারণ সি সি রেজল্যুশন রেজল্যুশন ধারণা নেই। অন্যান্য কাঠামোতে থাকা সি স্ট্রাকচারগুলি বাইরের কাঠামোর সুযোগে ঢুকে যায়।


struct abort
{
    int x;
};

int main()
{
    abort();
    return 0;
}

সি ++ তে 0 প্রস্থান কোড বা সি তে 3 দিয়ে ফিরে আসে।

এই কৌশলটি সম্ভবত আরও কিছু আকর্ষণীয় করার জন্য ব্যবহার করা যেতে পারে, তবে আমি একটি কন্সট্রকটার তৈরির একটি ভাল উপায় মনে করতে পারি না যা সি-র পছন্দের হতে পারে। আমি কপি কন্সট্রকটরের সাথে একই বিরক্তিকর উদাহরণ তৈরি করার চেষ্টা করেছি, যা একটি যুক্তি দেয় পাস করা হবে, যদিও একটি বরং পোর্টেবল ফ্যাশন:

struct exit
{
    int x;
};

int main()
{
    struct exit code;
    code.x=1;

    exit(code);

    return 0;
}

ভিসি ++ 2005 সি ++ মোডে কম্পাইল করতে অস্বীকার করেছে, যদিও, "প্রস্থান কোড" কীভাবে পুনর্নির্ধারণ করা হয়েছিল তার অভিযোগ। (আমি মনে করি এটি একটি কম্পাইলার বাগ, যতক্ষণ না আমি হঠাৎ প্রোগ্রামটি কিভাবে ভুলে গেছি।) যদিও সি হিসাবে কম্পাইল করার সময় এটি প্রক্রিয়াকরণের প্রস্থান কোডের সাথে প্রস্থান করে।





c