নালপ্টরকে কি uintptr_t এ রূপান্তর করা যায়? বিভিন্ন সংকলক একমত না


10

এই প্রোগ্রামটি বিবেচনা করুন:

#include <cstdint>
using my_time_t = uintptr_t;

int main() {
    const my_time_t t = my_time_t(nullptr);
}

এটি এমএসভিসি v19.24 দিয়ে সংকলন করতে ব্যর্থ হয়েছে:

<source>(5): error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'my_time_t'
<source>(5): note: A native nullptr can only be converted to bool or, using reinterpret_cast, to an integral type
<source>(5): error C2789: 't': an object of const-qualified type must be initialized
<source>(5): note: see declaration of 't'

Compiler returned: 2

তবে ঝাঁকুনি (9.0.1) এবং জিসিসি (9.2.1) কোনও ত্রুটি ছাড়াই এই কোডটি "খাওয়া" করুন।

আমি এমএসভিসি আচরণটি পছন্দ করি তবে এটি কি স্ট্যান্ডার্ড দ্বারা নিশ্চিত? অন্য কথায় এটি কি ঝনঝন / জিসিসি তে বাগ আছে বা এটি স্ট্যান্ডার্ডটি ব্যাখ্যা করা সম্ভব যে এটি জিসিসি / কলং থেকে সঠিক আচরণ?


2
আমি এটি কোনও ফাংশন-স্টাইলের কাস্ট থেকে অনুলিপি হিসাবে পাঠ করেছি। তারপরে এটি সংকলক দ্বারা সি ++ জনের একটি হিসাবে "এটি সংকলন করা যায় না এমনকি" হিসাবে ব্যাখ্যা করে । অভিনেত্রীর ব্যাখ্যা কীভাবে
সংকলিত হয়

যতদূর আমি সচেতন এমএসভিসি v19.24 একটি সি ++ 11 মোড সমর্থন করে না। আপনি কি এর পরিবর্তে C ++ 14 বা C ++ 17 বোঝাতে চেয়েছিলেন?
আখরোট

উত্তর:


5

আমার মতে এমএসভিসি মান-অনুসারে আচরণ করছে না।

আমি এই উত্তরটি C ++ 17 (খসড়া N4659) তে ভিত্তি করে চলেছি, তবে সি ++ 14 এবং সি ++ 11 এর সমতুল্য শব্দ রয়েছে।

my_time_t(nullptr)একটি পোস্টফিক্স-এক্সপ্রেশন এবং কারণ my_time_tএটি একটি প্রকার এবং (nullptr)একটি প্রথম বন্ধনীযুক্ত আরম্ভকারী তালিকার একক অভিব্যক্তি, এটি হুবহু স্পষ্ট কাস্ট এক্সপ্রেশনের সমতুল্য। ( [expr.type.conv] / 2 )

স্পষ্ট ঢালাই এছাড়াও বিশেষ করে, কয়েক বিভিন্ন নির্দিষ্ট সি ++ (এক্সটেনশনগুলি সহ) কাস্ট চেষ্টা করে reinterpret_cast। ( [Expr.cast] /4.4 ) কাস্ট আগে চেষ্টা reinterpret_castহয় const_castএবং static_cast(এক্সটেনশনগুলি সহ এবং একযোগে), কিন্তু এর মধ্যে কোনোটিই কাস্ট করতে পারেন std::nullptr_tঅবিচ্ছেদ্য টাইপ।

তবে reinterpret_cast<my_time_t>(nullptr)সফল হওয়া উচিত কারণ [expr.reinter ব্যাখ্যা.cast] / 4 বলছে যে প্রকারের মানকে std::nullptr_tএকটি অবিচ্ছেদ্য প্রকারে রূপান্তর করা যেতে পারে যেমন দ্বারা reinterpret_cast<my_time_t>((void*)0), যা সম্ভব কারণ my_time_t = std::uintptr_tসমস্ত পয়েন্টার মানগুলিকে উপস্থাপনের জন্য যথেষ্ট প্রকারের আকার হওয়া উচিত এবং এই অবস্থার অধীনে একই স্ট্যান্ডার্ড অনুচ্ছেদে void*অবিচ্ছেদ্য ধরণের রূপান্তর করতে দেয় ।

এটি বিশেষত আশ্চর্যজনক যে কার্যকরী স্বরলিপি ব্যবহারের পরিবর্তে কাস্ট স্বরলিপি ব্যবহার করা হলে এমএসভিসি রূপান্তরকে অনুমতি দেয়:

const my_time_t t = (my_time_t)nullptr;

1
হাঁ। দ্রষ্টব্য যে static_castবিশেষত সি-স্টাইলের ladালাই মইকে ফাঁদে ফেলার উদ্দেশ্যে কিছু মামলা রয়েছে (উদাহরণস্বরূপ, অস্পষ্ট ভিত্তিতে সি-স্টাইলের castালাই একটি static_castবদলে তৈরি করা নয় reinterpret_cast), তবে এখানে কোনও কিছুই প্রযোজ্য নয়।
টিসি

my_time_t(nullptr)সংজ্ঞা অনুসারে একই (my_time_t)nullptr, সুতরাং এমএসভিসি অবশ্যই একটি গ্রহণ এবং অন্যটিকে প্রত্যাখ্যান করা ভুল।
রিচার্ড স্মিথ

2

যদিও আমি এই ওয়ার্কিং ড্রাফ্ট সি ++ স্ট্যান্ডার্ড (২০১৪ সাল) তে কোনও অবিচ্ছেদ্য ধরণের রূপান্তর নিষিদ্ধ বলে কোনও স্পষ্ট উল্লেখ খুঁজে পাই না , তবে এমন রূপান্তর অনুমোদিত কিনা তাও উল্লেখ নেই!std::nullptr_t

যাইহোক, থেকে রুপান্তরের ক্ষেত্রে std::nullptr_tকরতে bool হয় স্পষ্টভাবে উল্লেখ করেছে:

৪.১২ বুলিয়ান রূপান্তরগুলি
পাটিগণিত, আনস্কোপড গণনা, পয়েন্টার বা পয়েন্টার থেকে সদস্য প্রকারের মূল প্রকারকে টাইপ বুলের একটি মূলতে রূপান্তরিত করা যেতে পারে। একটি শূন্য মান, নাল পয়েন্টার মান বা নাল সদস্য পয়েন্টার মানকে মিথ্যে রূপান্তর করা হয়; অন্য যে কোনও মানকে সত্যে রূপান্তরিত করা হয়। ডাইরেক্ট-ইনিশিয়ালাইজের জন্য (.5.৫), স্টাড :: নালপ্টর_ টাইপের একটি মূল্যকে বুল টাইপের একটি মূলতে রূপান্তর করা যেতে পারে; ফলাফল মান মিথ্যা।

আরও, এই খসড়া নথির একমাত্র জায়গা যেখানে std::nullptr_tঅবিচ্ছেদ্য ধরণের রূপান্তরকরণের কথা বলা হয়েছে, এটি "পুনরায় ব্যাখ্যা_কাস্ট" বিভাগে রয়েছে:

5.2.10 কাস্ট পুনরায় ব্যাখ্যা করুন
...
(4) একটি পয়েন্টারটি সুস্পষ্টভাবে কোনও ধরণের ইন্টিগ্রাল ধরণের কাছে ধারণ করতে পারে যাতে এটি ধরে রাখতে পারে। ম্যাপিং ফাংশনটি বাস্তবায়ন-সংজ্ঞায়িত। [দ্রষ্টব্য: এটি অন্তর্নিহিত মেশিনের ঠিকানা কাঠামো জানেন যারা তাদের জন্য উদ্বেগজনক হবে না intended - শেষ নোট] std :: nullptr_t প্রকারের একটি মান একটি অবিচ্ছেদ্য প্রকারে রূপান্তরিত হতে পারে; রূপান্তরটির একই অর্থ এবং বৈধতা রয়েছে (অকার্যকর *) 0 এর সাথে ইন্টিগ্রাল টাইপের রূপান্তর as [দ্রষ্টব্য: একটি পুনরায় ব্যাখ্যা_কাস্ট কোনও ধরণের মানকে std :: nullptr_t প্রকারে রূপান্তর করতে ব্যবহার করা যাবে না। - শেষ নোট]

সুতরাং, এই দুটি পর্যবেক্ষণ থেকে, কেউ (আইএমএইচও) যুক্তিসঙ্গতভাবে অনুমান করতে পারে যে সংকলকটি MSVCসঠিক।

সম্পাদনা : তবে, "ফাংশনাল নোটেশন কাস্ট" আপনার ব্যবহারের বিপরীতটি সম্ভবত প্রস্তাবিত হতে পারে! MSVCকম্পাইলার, একটি সি-শৈলী ঢালাই ব্যবহার উদাহরণস্বরূপ কোন সমস্যা রয়েছে:

uintptr_t answer = (uintptr_t)(nullptr);

তবে (আপনার কোড হিসাবে), এটি এই সম্পর্কে অভিযোগ করে:

uintptr_t answer = uintptr_t(nullptr); // error C2440: '<function-style-cast>': cannot convert from 'nullptr' to 'uintptr_t'

তবুও, একই খসড়া স্ট্যান্ডার্ড থেকে:

5.2.3 স্পষ্টত ধরণের রূপান্তর (ক্রিয়ামূলক স্বরলিপি)
(1) একটি প্রথম-টাইপ-নির্দিষ্টকরণকারী (7.1.6.2) বা টাইপনেম-স্পেসিফায়ার (14.6) এর পরে একটি প্রথম বন্ধনীযুক্ত এক্সপ্রেশন-তালিকাটি বর্ণিত তালিকা প্রদত্ত নির্দিষ্ট ধরণের মান নির্মান করে। যদি অভিব্যক্তি তালিকার একটি একক অভিব্যক্তি হয় তবে ধরণের রূপান্তর এক্সপ্রেশনটি সংশ্লিষ্ট কাস্ট এক্সপ্রেশন (5.4) এর সমতুল্য (সংজ্ঞায়িত, এবং যদি অর্থ সংজ্ঞায়িত হয়) হয়। ...

"সংশ্লিষ্ট কাস্ট এক্সপ্রেশন (5.4)" সি-স্টাইলের castালাকে বোঝায়।


0

সবগুলি স্ট্যান্ডার্ড কনফরম্যান্ট (সি ++ এর জন্য রেফারেন্ট ড্রাফট এন 4659)।

nullptr [lex.nullptr] এ হিসাবে সংজ্ঞায়িত করা হয়েছে:

পয়েন্টার আক্ষরিক হ'ল মূল শব্দটি নাল্পটার। এটি std :: nullptr_t প্রকারের একটি মূল্যবান। [দ্রষ্টব্য: ..., এই ধরণের একটি মূল্য একটি নাল পয়েন্টার ধ্রুবক এবং নাল পয়েন্টার মান বা নাল সদস্য পয়েন্টার মানে রূপান্তর করা যেতে পারে]]

এমনকি যদি নোটগুলি মানহীন হয় তবে এটি পরিষ্কার করে দেয় যে মানটির nullptrজন্য এটি একটি নাল পয়েন্টার মানে রূপান্তরিত হবে বলে আশা করা হচ্ছে ।

আমরা পরবর্তীতে [কনফিডার] এ খুঁজে পাই:

একটি নাল পয়েন্টার ধ্রুবক হল মান শূন্যের সাথে একটি পূর্ণসংখ্যার শাব্দিক বা প্রকারের std :: nullptr_t টাইপ করা। একটি নাল পয়েন্টার ধ্রুবক একটি পয়েন্টার ধরণের রূপান্তর করা যেতে পারে; .... ইন্টিগ্রাল টাইপের একটি নাল পয়েন্টার ধ্রুবক std :: nullptr_t প্রকারের রূপে রূপান্তর করা যায়।

এখানে আবার স্ট্যান্ডার্ড দ্বারা যা প্রয়োজন তা হ'ল এটি একটিতে 0রূপান্তরিত হতে পারে std::nullptr_tএবং এটি যে nullptrকোনও পয়েন্টার ধরণের রূপান্তরিত হতে পারে।

আমার পড়া মান কিনা কোন প্রয়োজন রয়েছে nullptrযাবে সরাসরি অবিচ্ছেদ্য টাইপ বা না রূপান্তরিত। যে বিন্দু থেকে:

  • এমএসভিসির একটি কঠোর পঠন রয়েছে এবং রূপান্তরটি নিষেধ করেছে
  • ঝনঝন এবং জিসিসি আচরণ করে যেন কোনও মধ্যস্থতাকারী void *রূপান্তর জড়িত।

1
আমি মনে করি এটি ভুল। কিছু নাল পয়েন্টার ধ্রুবক শূন্য মান পূর্ণসংখ্যা লিটারেল, কিন্তু nullptrকারণ এটি অ অবিচ্ছেদ্য টাইপ আছে না std::nullptr_t। 0 std::nullptr_tমানকে রূপান্তর করা যায় তবে আক্ষরিক ক্ষেত্রে নয় nullptr। এটি সমস্ত ইচ্ছাকৃত, std::nullptr_tঅনিচ্ছাকৃত রূপান্তরগুলি রোধ করার জন্য আরও সীমাবদ্ধ প্রকার।
এমসাল্টারস

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