সি ++ 0 এক্সে সংকীর্ণ রূপান্তর। এটি কি কেবল আমি, নাকি এই শব্দটি কোনও ব্রেকিংয়ের মতো?


86

সি ++ 0x নিম্নলিখিত কোড এবং অনুরূপ কোড অসুস্থ গঠিত করা, কারণ এটি একটি তথাকথিত প্রয়োজন যাচ্ছে সংকীর্ণ রূপান্তর একটি এর doubleএকটি থেকে int

int a[] = { 1.0 };

আমি ভাবছি যে এই ধরণের সূচনাটি বাস্তব বিশ্বের কোডে বেশি ব্যবহৃত হয়। এই পরিবর্তন দ্বারা কতটি কোড ভেঙে যাবে? আপনার কোডটি এটিকে সংশোধন করার জন্য কি অনেক চেষ্টা করা হচ্ছে, যদি আপনার কোডটি কিছুটা প্রভাবিত হয়?


রেফারেন্সের জন্য, এন 3225 এর 8.5.4 / 6 দেখুন

সংকীর্ণ রূপান্তর হ'ল অন্তর্নিহিত রূপান্তর

  • ভাসমান-বিন্দু টাইপ থেকে পূর্ণসংখ্যার প্রকারে বা
  • দীর্ঘ ডাবল থেকে ডাবল বা ভাসমান, বা দ্বৈত থেকে ভাসা পর্যন্ত, যেখানে উত্সটি একটি ধ্রুবক অভিব্যক্তি এবং রূপান্তরকরণের পরে আসল মান এমন মানগুলির সীমার মধ্যে থাকে যা উপস্থাপিত হতে পারে (এমনকি যদি এটি সঠিকভাবে উপস্থাপন করা যায় না), বা
  • একটি পূর্ণসংখ্যা টাইপ বা অপরিশোধিত গণনা প্রকার থেকে শুরু করে fl ওটিং-পয়েন্ট টাইপের দিকে, যেখানে উত্সটি একটি ধ্রুবক অভিব্যক্তি এবং রূপান্তরকরণের পরে আসল মান লক্ষ্যমাত্রার সাথে মানানসই হয় এবং মূল ধরণে ফিরে রূপান্তরিত হলে আসল মান উত্পাদন করে, বা
  • একটি পূর্ণসংখ্যা টাইপ বা অপরিশোধিত গণনা টাইপ থেকে একটি পূর্ণসংখ্যার ধরণে যা মূল ধরণের সমস্ত মানকে উপস্থাপন করতে পারে না, উত্সটি ধ্রুবক অভিব্যক্তি এবং রূপান্তরকরণের পরে আসল মান লক্ষ্যমাত্রার সাথে মানানসই হয় এবং আসল মানটি যখন উত্পাদন করে তখন মূল ধরণে ফিরে রূপান্তরিত।

4
এটি কেবল ইনবিল্ট প্রকারের আরম্ভের জন্য বৈধ বলে ধরে নেওয়া, এটি কীভাবে ক্ষতি করবে তা আমি দেখতে পাচ্ছি না। অবশ্যই, এটি কিছু কোড ভঙ্গ করতে পারে। তবে ঠিক করা সহজ হওয়া উচিত।
জোহান কোটলিনস্কি

4
@ জন ডিবলিং: না, যখন লক্ষ্যটি হুবহু ধরণের দ্বারা যথাযথভাবে উপস্থাপন করা যেতে পারে তখন সূচনাটি খারাপভাবে তৈরি হয় না। (এবং 0ইতিমধ্যে intযাইহোক এটি ইতিমধ্যে ))
Aschepler

4
@ নিম: দ্রষ্টব্য যে এটি কেবল {কোঁকড়া ধনুর্বন্ধক আরম্ভকারীদের মধ্যেই খারাপ-গঠিত }, এবং এগুলির একমাত্র উত্তরাধিকার ব্যবহার অ্যারে এবং পিওডি স্ট্রাইকগুলির জন্য। এছাড়াও, যদি বিদ্যমান কোডটিতে তাদের স্পষ্ট বর্ণিত কাস্ট থাকে তবে তা ভাঙবে না।
aschepler

4
ওয়ার্কিং পেপার হিসাবে @ j_random_hacker int a = 1.0;এখনও বৈধ।
জোহানেস স্কাউব -

4
@ লিটব: ধন্যবাদ আসলে আমি বুঝতে পেরেছি তবে হতাশাব্যঞ্জক - আইএমএইচও সি ++ এর শুরু থেকেই সমস্ত সংকীর্ণ রূপান্তরগুলির জন্য সুস্পষ্ট বাক্য গঠন প্রয়োজন হলে আরও ভাল হত।
j_random_hacker

উত্তর:


41

আমি যখন এই জিসিসি ব্যবহার করেছি তখন আমি এই ব্রেকিং পরিবর্তনে চলে এসেছিলাম সংকলক কোডটির জন্য এই জাতীয় একটি ত্রুটি মুদ্রণ করেছে:

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {i & 0xFFFFFFFF, i >> 32};
}

কার্য void foo(const long long unsigned int&):

ত্রুটি: ভিতরে (((long long unsigned int)i) & 4294967295ull)থেকে রূপান্তরকরণ long long unsigned intto unsigned int}

ত্রুটি: ভিতরে (((long long unsigned int)i) >> 32)থেকে রূপান্তরকরণ long long unsigned intto unsigned int}

ভাগ্যক্রমে, ত্রুটি বার্তাগুলি সোজা ছিল এবং ঠিক করা সহজ:

void foo(const unsigned long long &i)
{
    unsigned int a[2] = {static_cast<unsigned int>(i & 0xFFFFFFFF),
            static_cast<unsigned int>(i >> 32)};
}

কোডটি একটি বাহ্যিক গ্রন্থাগারে ছিল, একটি ফাইলে কেবল দুটি ঘটনা ছিল। আমি ভাবি না যে ব্রেকিং পরিবর্তনটি অনেক কোডকে প্রভাবিত করবে। Novices পারে পেতে বিভ্রান্ত, যদিও।


9

আমি নিজের মধ্যে বিস্মিত ও হতাশ হয়ে জানতে পারি যে আমি গত 12 বছরে লিখেছি যে কোনও সি ++ কোডে এই ধরণের সমস্যা ছিল। তবে বেশিরভাগ সংকলকগণ যে কোনও সংকলন-কালীন "সংকীর্ণতা" সম্পর্কে সতর্কতা দিতেন, যদি না আমি কিছু মিস করি।

এগুলি কি সংকীর্ণ রূপান্তরগুলি?

unsigned short b[] = { -1, INT_MAX };

যদি তা হয়, তবে আমি মনে করি তারা আপনার ভাসমান ধরণের চেয়ে অবিচ্ছেদ্য ধরণের উদাহরণে কিছুটা বেশি আসতে পারে।


4
আমি বুঝতে পারছি না কেন আপনি কোডে এটি খুঁজে পাওয়া কোনও অস্বাভাবিক বিষয় হবে। USHRT_MAX এর পরিবর্তে -1 বা INT_MAX ব্যবহারের মধ্যে যুক্তিটি কী? ২০১০ সালের শেষের দিকে কি ইউএসএইচআরT_MAX ছিল না?

8

একটি বাস্তব উদাহরণ যা আমি মুখোমুখি হয়েছি:

float x = 4.2; // an input argument
float a[2] = {x-0.5, x+0.5};

সংখ্যাগত আক্ষরিক স্পষ্টতই doubleযা প্রচারের কারণ হয়।


4
সুতরাং এটি floatলিখে তৈরি করুন 0.5f। ;)
আন্ডারস্কোর_২

4
@ মাউন্ডসওয়ার_ডি টাইপেফ floatবা টেমপ্লেট প্যারামিটার (কমপক্ষে নির্ভুলতার ক্ষতি ছাড়াই) কাজ করে না তবে মূল বিষয়টি হল লিখিত কোডটি সঠিক শব্দার্থবিদ্যার সাথে কাজ করে এবং সি ++ 11 এর সাথে ত্রুটি হয়ে ওঠে। অর্থাৎ, "ব্রেকিং চেঞ্জ" এর সংজ্ঞা।
জেড

7

কেউ যদি এরকম কিছু দ্বারা ধরা পড়ে যায় তবে আমি এতটা অবাক হব না:

float ra[] = {0, CHAR_MAX, SHORT_MAX, INT_MAX, LONG_MAX};

(আমার বাস্তবায়নে, শেষ দুটি দীর্ঘ / ইন / লংতে রূপান্তরিত হওয়ার পরে একই ফলাফল তৈরি করে না, তাই সংকীর্ণ হয়)

যদিও এটি কখনও লেখার কথা মনে নেই। এটি কেবল তখনই কার্যকর যখন সীমাতে একটি আনুমানিক কোনও কিছুর জন্য কার্যকর।

এটি কমপক্ষে অস্পষ্টভাবে প্রশ্রয়জনক বলে মনে হয়:

void some_function(int val1, int val2) {
    float asfloat[] = {val1, val2};    // not in C++0x
    double asdouble[] = {val1, val2};  // not in C++0x
    int asint[] = {val1, val2};        // OK
    // now do something with the arrays
}

তবে এটি পুরোপুরি বিশ্বাসযোগ্য নয়, কারণ যদি আমি জানতে পারি যে আমার ঠিক দুটি মান রয়েছে তবে কেন এগুলি কেবল অ্যারের পরিবর্তে রাখবে float floatval1 = val1, floatval1 = val2;? অনুপ্রেরণা কী, যদিও, কেন এটি সংকলন করা উচিত (এবং কাজটি দেওয়া হয়েছে যে সঠিকতার ক্ষতি প্রোগ্রামের জন্য গ্রহণযোগ্য নির্ভুলতার মধ্যে রয়েছে), যখন করা float asfloat[] = {val1, val2};উচিত নয়? যেভাবেই আমি দুটি ইনট থেকে দুটি ফ্লোট শুরু করছি, এটি কেবল এক ক্ষেত্রে দুটি ভাসমান একটি সামগ্রীর সদস্য হতে পারে।

এটি বিশেষত কঠোর বলে মনে হয় যেখানে অবিচ্ছিন্ন অভিব্যক্তি সংকীর্ণ রূপান্তর ঘটায় যদিও (নির্দিষ্ট প্রয়োগের ক্ষেত্রে), উত্স ধরণের সমস্ত মান গন্তব্য প্রকারের মধ্যে উপস্থাপিত হয় এবং তাদের মূল মানগুলিতে ফিরে যেতে পারে:

char i = something();
static_assert(CHAR_BIT == 8);
double ra[] = {i}; // how is this worse than using a constant value?

ধরে নেই যে কোনও ত্রুটি নেই, সম্ভবত রূপান্তরটি সুস্পষ্ট করার জন্য এই সমাধানটি সর্বদা। আপনি ম্যাক্রোগুলির সাথে অদ্ভুত কিছু করছেন না, তবে আমি মনে করি যে অ্যারের প্রারম্ভকালে কেবল অ্যারের প্রকারের নিকটে বা কমপক্ষে এমন কিছু উপস্থাপন করা হবে যা কোনও টেম্পলেট প্যারামিটারের উপর নির্ভরশীল হতে পারে appears সুতরাং একটি oseালাই সহজ হওয়া উচিত, যদি ভার্বোস হয়।


9
"যদি আমি জানি আমার ঠিক দুটি মান রয়েছে তবে এগুলিকে কেন অ্যারে রাখি" - যেমন কারণ ওপেনজিএল এর মতো একটি এপিআই এর প্রয়োজন হয়।
জর্জি ফ্রিত্শে

5

উদাহরণস্বরূপ: আপনার সিএফএলএগএস-তে কোন-সংকীর্ণ যুক্ত করার চেষ্টা করুন

CFLAGS += -std=c++0x -Wno-narrowing

বা সিপিএফএফএলএগএস সি ++ সংকলকগুলির ক্ষেত্রে (অবশ্যই এটি আপনার বিল্ড সিস্টেম বা আপনার
মেকফিলের

4

সংকীর্ণ রূপান্তর ত্রুটিগুলি অন্তর্ভুক্ত পূর্ণসংখ্যার প্রচারের বিধিগুলির সাথে খারাপভাবে যোগাযোগ করে।

কোডটির মতো দেখতে আমার একটি ত্রুটি ছিল looked

struct char_t {
    char a;
}

void function(char c, char d) {
    char_t a = { c+d };
}

যা সংকীর্ণ রূপান্তর ত্রুটি তৈরি করে (যা মান অনুসারে সঠিক)। কারণটি হ'ল cএবং dসুস্পষ্টভাবে প্রচারিত হয় intএবং ফলস্বরূপ intপ্রাথমিকের তালিকায় চরে সংকীর্ণ হওয়ার অনুমতি নেই।

OTOH

void function(char c, char d) {
    char a = c+d;
}

অবশ্যই এখনও ঠিক আছে (অন্যথায় সমস্ত নরক আলগা হয়ে যাবে)। তবে আশ্চর্যের বিষয়, এমনকি

template<char c, char d>
void function() {
    char_t a = { c+d };
}

যদি c এবং d এর যোগফল CHAR_MAX এর চেয়ে কম হয় তবে এটি একটি সতর্কতা ছাড়াই সংকলন করে। আমি এখনও সি ++ 11 এ এটি একটি ত্রুটি বলে মনে করি, তবে সেখানকার লোকেরা অন্যথায় ভাবেন - সম্ভবত কারণ যেহেতু অন্তর্নিহিত পূর্ণসংখ্যার রূপান্তর (যা অতীতের একটি প্রতিলিপি, লোকেরা কোড লিখেছিল তা থেকে মুক্তি না পেয়ে এটি সমাধান করা সহজ নয়) মত char a=b*c/dও প্রত্যাশিত এটা কাজ এমনকি যদি (খ * গ)> CHAR_MAX) অথবা রূপান্তর ত্রুটি (যা সম্ভবত একটি ভাল জিনিস সংকীর্ণ)।


আমি নিম্নলিখিতটিতে ছুটে এসেছি যা সত্যই বিরক্তিকর বাজে কথা: unsigned char x; static unsigned char const m = 0x7f; ... unsigned char r = { x & m };<- {inside এর ভিতরে সংকীর্ণ রূপান্তর} সত্যি? সুতরাং অপারেটর এবং স্বতন্ত্রভাবে স্বাক্ষরযুক্ত অক্ষরগুলিকে ইন্টিতে রূপান্তর করে? আচ্ছা, আমি খেয়াল করি না, ফলাফলটি এখনও একটি স্বাক্ষরবিহীন চর, গ্যারান্টিযুক্ত।
কার্লো উড

"অন্তর্ভুক্ত পূর্ণসংখ্যার রূপান্তর " প্রচার?
কৌতূহলী

2

এটি প্রকৃতপক্ষে একটি ব্রেকিং পরিবর্তন ছিল কারণ এই বৈশিষ্ট্যটির সাথে বাস্তব জীবনের অভিজ্ঞতাটি দেখিয়েছে যে সিসি ++ 03 কোড ঘাঁটি সি ++ 11 এ পোর্টিং সহ বাস্তব জীবনের বেদনার কারণে জিসিসি অনেক ক্ষেত্রে ত্রুটি থেকে একটি সতর্কতায় রূপান্তরিত হয়েছিল। একটি জিসিসি বাগ রিপোর্টে এই মন্তব্যটি দেখুন :

স্ট্যান্ডার্ডটির কেবল প্রয়োজন যে "একটি অনুসারী বাস্তবায়ন কমপক্ষে একটি ডায়াগনস্টিক বার্তা জারি করবে" সুতরাং একটি সতর্কতার সাথে প্রোগ্রাম সংকলন করার অনুমতি দেওয়া হয়। অ্যান্ড্রু যেমন বলেছিলেন, -আরওয়্যার = সংকীর্ণকরণ আপনি চাইলে এটিকে ত্রুটি তৈরি করতে দেয়।

জি ++ ৪. an একটি ত্রুটি দিয়েছে তবে এটি ইচ্ছাকৃতভাবে একটি সতর্কবার্তায় পরিণত হয়েছিল ৪. was এর জন্য কারণ অনেক লোক (আমার অন্তর্ভুক্ত) দেখা গেছে যে সংকীর্ণ রূপান্তরগুলি যেখানে বড় সি ++ 03 কোডবাসকে সি ++ 11 হিসাবে সংকলনের চেষ্টা করার সময় সর্বাধিক সমস্যা দেখা দেয় । পূর্বে সুসংগঠিত কোড যেমন চর সি [] = {i, 0}; (যেখানে আমি কেবল চরের সীমার মধ্যে থাকব) ত্রুটিগুলির কারণে এবং চরকে সি তে পরিবর্তন করতে হয়েছিল [] = {(চর) i, 0}


1

দেখে মনে হচ্ছে জিসিসি -৪.7 আর রূপান্তর সংকীর্ণ করার জন্য ত্রুটি দেয় না, পরিবর্তে সতর্কতা দেয়।

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