সি ++ এ দীর্ঘ দীর্ঘ ইন্ট বনাম লং ইন্ট বনাম ইন্ট 64_t


87

সি ++ টাইপ বৈশিষ্ট্য ব্যবহার করার সময় আমি কিছু অদ্ভুত আচরণের অভিজ্ঞতা পেয়েছি এবং আমার সমস্যাটিকে এই অদ্ভুত সামান্য সমস্যার দিকে সংকুচিত করেছি যার জন্য আমি এক টন ব্যাখ্যা দেব যেহেতু আমি ভুল ব্যাখ্যা দেওয়ার জন্য কিছু খোলা রাখতে চাই না।

বলুন আপনার মতো প্রোগ্রাম রয়েছে:

#include <iostream>
#include <cstdint>

template <typename T>
bool is_int64() { return false; }

template <>
bool is_int64<int64_t>() { return true; }

int main()
{
 std::cout << "int:\t" << is_int64<int>() << std::endl;
 std::cout << "int64_t:\t" << is_int64<int64_t>() << std::endl;
 std::cout << "long int:\t" << is_int64<long int>() << std::endl;
 std::cout << "long long int:\t" << is_int64<long long int>() << std::endl;

 return 0;
}

জিসিসির সাথে 32-বিট সংকলন উভয় (এবং 32- এবং 64-বিট এমএসভিসি সহ), প্রোগ্রামটির আউটপুট হবে:

int:           0
int64_t:       1
long int:      0
long long int: 1

তবে, 64-বিট জিসিসি সংকলনের ফলে প্রোগ্রামটি আউটপুট দেবে:

int:           0
int64_t:       1
long int:      1
long long int: 0

যেহেতু এই অদ্ভুত long long intএকটি স্বাক্ষরিত 64-বিট পূর্ণসংখ্যা এবং সব ইন্টেন্টগুলি এবং উদ্দেশ্যের, অভিন্ন জন্য হয় long intএবং int64_tধরনের, সুতরাং যুক্তি, int64_t, long intএবং long long intসমাবেশ উত্পন্ন যখন এই ধরনের ব্যবহার অভিন্ন হয় - সমতুল্য ধরনের হতে হবে। এক নজর stdint.hআমাকে বলছে কেন:

# if __WORDSIZE == 64
typedef long int  int64_t;
# else
__extension__
typedef long long int  int64_t;
# endif

-৪-বিট সংকলনে, int64_tহয় long intনা long long int(স্পষ্টতই)।

এই পরিস্থিতির সমাধান খুব সহজ:

#if defined(__GNUC__) && (__WORDSIZE == 64)
template <>
bool is_int64<long long int>() { return true; }
#endif

তবে এটি মারাত্মকভাবে হ্যাকিশ এবং ভালভাবে স্কেল করে না (পদার্থের প্রকৃত ফাংশন uint64_tইত্যাদি)। সুতরাং আমার প্রশ্নটি হ'ল: সংকলককে বলার মতো কোনও উপায় আছে যে একটিও long long intএকই int64_t, long intতেমন?


আমার প্রাথমিক চিন্তাভাবনাগুলি হ'ল সি / সি ++ টাইপ সংজ্ঞাগুলি যেভাবে কাজ করে তার কারণে এটি সম্ভব নয়। সংকলকটিতে প্রাথমিক তথ্য প্রকারের সমতুল্যতা নির্দিষ্ট করার কোনও উপায় নেই, যেহেতু এটি সংকলকটির কাজ (এবং এতে অনেক কিছুই ভেঙে যেতে পারে) এবং typedefকেবল একটি পথ যায়।

আমি এখানে উত্তর পাওয়ার ব্যাপারেও খুব বেশি উদ্বিগ্ন নই, যেহেতু এটি একটি সুপার-ডুপার এজ এজ যেটি আমি সন্দেহ করি না যে উদাহরণগুলি যখন ভয়াবহভাবে সংকলিত না হয় তখন কখনই কেউ তার যত্ন নেবে (এর অর্থ কি এটি সম্প্রদায়ের উইকি হওয়া উচিত?) ।


সংযোজন : যে কারণে আমি আরও সহজ উদাহরণের পরিবর্তে আংশিক টেম্পলেট বিশেষায়নের ব্যবহার করছি:

void go(int64_t) { }

int main()
{
    long long int x = 2;
    go(x);
    return 0;
}

যে বলা উদাহরণ এখনও সংকলন করা হবে, যেহেতু long long intএকটি স্পষ্টত রূপান্তরিত হয় int64_t


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

template <typename T>
struct some_type_trait : boost::false_type { };

template <>
struct some_type_trait<int64_t> : boost::true_type { };

এই উদাহরণে, some_type_trait<long int>একটি হবে boost::true_type, তবে some_type_trait<long long int>হবে না। যদিও এটি সি +++ এর ধরণের ধারণাগুলিতে উপলব্ধি করে, এটি কাম্য নয়।

আর একটি উদাহরণ কোয়ালিফায়ার ব্যবহার করে same_type(যা সি ++ 0 এক্স কনসেপ্টে ব্যবহার করা বেশ সাধারণ):

template <typename T>
void same_type(T, T) { }

void foo()
{
    long int x;
    long long int y;
    same_type(x, y);
}

সেই উদাহরণটি সংকলন করতে ব্যর্থ হয়েছে, যেহেতু সি ++ (সঠিকভাবে) দেখতে পান যে প্রকারগুলি আলাদা। g ++ এর মতো একটি ত্রুটি দিয়ে সংকলন করতে ব্যর্থ হবে: কোনও ফাংশন কল নেই same_type(long int&, long long int&)

আমি জোর দিয়ে বলতে চাই যে আমি বুঝতে পেরেছি কেন এটি হচ্ছে, তবে আমি এমন একটি কাজের সন্ধান করছি যা পুরো জায়গা জুড়েই কোডটি পুনরাবৃত্তি করতে বাধ্য করে না।


কৌতূহলের বাইরে, আপনার নমুনা প্রোগ্রামটি কি sizeofপ্রতিটি ধরণের জন্য একই ফলাফল দেয় ? সম্ভবত সংকলক আকারের সাথে long long intআলাদাভাবে আচরণ করছে ।
ব্লেয়ার হলোয়ে

আপনি কি সি ++ 0x সক্ষম দিয়ে সংকলন করেছেন? সি ++ ০ টি নেই <cstdint>, তাই সম্ভবত এটি বলতে হবে "এটি একটি এক্সটেনশন" (যা এটি) এটি প্রচার করছে।
GManNickG

হ্যাঁ, আমার সম্ভবত এটি নির্দিষ্ট করা উচিত ছিল যা আমি ব্যবহার করছি --std=c++0x। এবং হ্যাঁ sizeof(long long int) == sizeof(long int) == sizeof(int64_t) == 8,।
ট্র্যাভিস গোকেল

4
কেউ এখনও এটি উল্লেখ করেনি, তবে ক্ষেত্রে এটি উপেক্ষা করা হয়েছে: longএবং long longস্বতন্ত্র ধরণের (যদিও তাদের আকার এবং আকারের উপস্থাপনা রয়েছে)। int64_tসর্বদা অন্য বিদ্যমান ধরণের জন্য সর্বদা একটি নাম (এটির নাম থাকা সত্ত্বেও, typedefনতুন ধরণের তৈরি করে না, এটি ইতিমধ্যে বিদ্যমান ব্যক্তিকে কেবল একটি নাম দেয়)
এমএম

4
উত্তরগুলি / মন্তব্যগুলি থেকে একটি গুরুত্বপূর্ণ বিবৃতি অনুপস্থিত, যা আমাকে এই সহায়তা করেছিল যখন এই তিরস্কারটি আমাকে আঘাত করেছে: নির্ভরযোগ্যতার সাথে বিশেষজ্ঞ টেম্পলেটগুলির জন্য কখনও স্থির আকারের প্রকার ব্যবহার করবেন না। সর্বদা মৌলিক প্রকারগুলি ব্যবহার করুন এবং সমস্ত সম্ভাব্য কেসগুলি কভার করুন (আপনি যদি এই টেমপ্লেটগুলি ইনস্ট্যান্ট করতে স্থির-আকারের ধরণের ব্যবহার করেন)। সকল সম্ভব মামলা মানে যদি আপনার সাথে instantiate প্রয়োজন int16_t, তারপর সঙ্গে বিশেষজ্ঞ shortএবং intএবং আপনি সুরক্ষিত থাকবেন। (এবং signed charআপনি যদি দুঃসাহসী বোধ করেন তবে এর সাথে )
ইরাইফাই

উত্তর:


49

এরকম কিছু দেখতে আপনার 64৪-বিটে যাওয়ার দরকার নেই। int32_tসাধারণ 32-বিট প্ল্যাটফর্মগুলিতে বিবেচনা করুন। এটি typedefহিসাবে intবা হিসাবে হিসাবে সম্পাদিত হতে পারে long, তবে স্পষ্টতই একবারে দু'জনের মধ্যে একটি মাত্র। intএবং longঅবশ্যই স্বতন্ত্র প্রকারের।

int == int32_t == long32-বিট সিস্টেম তৈরি করে এমন কোনও কার্যকারিতা নেই তা দেখতে অসুবিধা নেই । একই কারণে, long == int64_t == long long64-বিট সিস্টেমগুলি তৈরি করার কোনও উপায় নেই ।

যদি আপনি করতে পারে, সম্ভব পরিণতি কোড বরং বেদনাদায়ক হবে যে ওভারলোড foo(int), foo(long)এবং foo(long long)- হঠাৎ তারা একই জমিদার জন্য দুটি সংজ্ঞা আছে চাই ?!

সঠিক সমাধানটি হ'ল আপনার টেমপ্লেট কোডটি সাধারণত কোনও সুনির্দিষ্ট ধরণের উপর নির্ভর করে না তবে সেই ধরণের বৈশিষ্ট্যের উপর নির্ভর করে। same_typeনির্দিষ্ট যুক্তির জন্য পুরো যুক্তিটি এখনও ঠিক থাকতে পারে:

long foo(long x);
std::tr1::disable_if(same_type(int64_t, long), int64_t)::type foo(int64_t);

অর্থাত্, ওভারলোডটি foo(int64_t)সংজ্ঞায়িত হয় না যখন এটি ঠিক একইরকম হয় foo(long)

[সম্পাদনা] সি ++ 11 দিয়ে এখন আমাদের এটি লেখার একটি মানক উপায় রয়েছে:

long foo(long x);
std::enable_if<!std::is_same<int64_t, long>::value, int64_t>::type foo(int64_t);

[সম্পাদনা] বা সি ++ ২০

long foo(long x);
int64_t foo(int64_t) requires (!std::is_same_v<int64_t, long>);

4
দুঃখজনক সংবাদটি হল, যেমন eg৪ বিট এমএসভিসি ১৯ (2017) এ sizeof() longএবং intঅভিন্ন, তবে std::is_same<long, int>::valueফিরে আসে false। ওএসএক্স হাইসিয়ারায় অ্যাপলক্ল্যাং 9.1 এ একই অদ্ভুততা।
এক্সএল 3

4
@ এক্স 3 এল: এটি অদ্ভুত নয়। কার্যত প্রতিটি সংকলক আইএসও সি 90 এর মধ্যে কমপক্ষে এরকম একটি জুড়ি রয়েছে।
এমএসএলটারস

এটি সত্য, তারা স্বতন্ত্র প্রকারের।
এক্সএল 3

6

আপনি কি জানতে চান যে কোনও টাইপটি একই রকম int64_t এর মতো কিনা বা আপনি কি কিছু জানতে চান 64 বিটস? আপনার প্রস্তাবিত সমাধানের ভিত্তিতে, আমি মনে করি আপনি পরবর্তী সম্পর্কে জিজ্ঞাসা করছেন। সেক্ষেত্রে আমি এমন কিছু করব

template<typename T>
bool is_64bits() { return sizeof(T) * CHAR_BIT == 64; } // or >= 64

4
আপনি কি একটি returnএবং সেমিকোলন মিস করছেন না ?
ক্যাসাব্ল্যাঙ্কা

4
তবুও, আপনার এটি ব্যবহার করা উচিত sizeof
বেন ভয়েগট

4
দীর্ঘ দীর্ঘ ইন্টি এবং লং ইনট একই আকার নয় কি না তা একই ধরণের নয়। আচরণটি ভ্রান্ত নয়। এটি কেবল সি ++।
লোগান ক্যাপাল্ডো

4
এটি নামমাত্র টাইপিংয়ের সীমাবদ্ধতা নয়। এটি অর্থহীন নামমাত্র টাইপিংয়ের একটি সীমাবদ্ধতা । পুরানো দিনগুলিতে, ডি ফ্যাক্টো স্ট্যান্ডার্ডটি ছিল short= 16 বিট, long= 32 বিট এবং int= নেটিভ আকার। 64-বিট এর এই দিন সালে intএবং longনা মানে আর কিছু।
dan04

4
@ ডান04: তারা আগের তুলনায় কম বেশি অর্থবহ হয় না। shortহয় অন্তত 16 বিট intঅন্তত 16 বিট, এবং longঅন্তত 32 বিট, সঙ্গে (পঙ্কিল স্বরলিপি অনুসরণ করে) শর্ট <= int- এ <= দীর্ঘ। আপনি যে "পুরানো দিনগুলি" উল্লেখ করেছেন তা কখনই ছিল না; ভাষা দ্বারা আরোপিত বিধিনিষেধের মধ্যে সর্বদা ভিন্নতা ছিল। "সমস্ত বিশ্বের একটি x86" মিথ্যাচারটি বয়স্কদের মতোই বিপজ্জনক "সমস্ত বিশ্বের একটি ভ্যাক্স ভ্রান্তি
কেইথ থম্পসন

1

সুতরাং আমার প্রশ্নটি: কম্পাইলারকে বলার মতো কোনও উপায় আছে যে দীর্ঘ দীর্ঘ অন্তরঙ্গটিও একটি int64_t, ঠিক যেমন দীর্ঘ ইনট?

এটি একটি ভাল প্রশ্ন বা সমস্যা, তবে আমি সন্দেহ করি উত্তরটি হ'ল না।

এছাড়াও, একটি একটি long intনাও হতে পারে long long int


# if __WORDSIZE == 64
typedef long int  int64_t;
# else
__extension__
typedef long long int  int64_t;
# endif

আমি বিশ্বাস করি যে এটি libc। আমার সন্দেহ হয় আপনি আরও গভীর হতে চান

জিসিসির সাথে 32-বিট সংকলন উভয় (এবং 32- এবং 64-বিট এমএসভিসি সহ), প্রোগ্রামটির আউটপুট হবে:

int:           0
int64_t:       1
long int:      0
long long int: 1

32-বিট লিনাক্স ILP32 ডেটা মডেল ব্যবহার করে। পূর্ণসংখ্যা, দীর্ঘ এবং পয়েন্টারগুলি 32-বিট। 64-বিট টাইপটি একটি long long

মাইক্রোসফ্ট ডেটা টাইপ রেঞ্জের রেঞ্জগুলি ডকুমেন্ট করে । বলার long longসমতুল্য __int64

তবে, 64-বিট জিসিসি সংকলনের ফলে প্রোগ্রামটি আউটপুট দেবে:

int:           0
int64_t:       1
long int:      1
long long int: 0

-৪-বিট লিনাক্স LP64ডেটা মডেল ব্যবহার করে । লংগুলি 64-বিট এবং long long64-বিট হয়। ৩২-বিটের মতো, মাইক্রোসফ্ট ডেটা টাইপ রেঞ্জের রেঞ্জগুলি নথিভুক্ত করে এবং লম্বা দীর্ঘ এখনও __int64

একটি ILP64ডেটা মডেল রয়েছে যেখানে সবকিছু 64৪-বিট। আপনার word32ধরণের সংজ্ঞা পেতে আপনাকে কিছু অতিরিক্ত কাজ করতে হবে । এছাড়াও 64-বিট প্রোগ্রামিং মডেলগুলির মতো কাগজপত্রগুলি দেখুন : কেন এলপি 64?


তবে এটি মারাত্মকভাবে হ্যাকিশ এবং ভাল স্কেল করে না (পদার্থের প্রকৃত ফাংশন, uint64_t ইত্যাদি) ...

হ্যাঁ, এটি আরও ভাল হয়। জিসিসি মিশ্রিত করে এবং ঘোষণাগুলির সাথে মেলে যা that৪ বিট প্রকারের গ্রহণযোগ্য বলে মনে করা হয়, সুতরাং আপনি কোনও নির্দিষ্ট ডেটা মডেল অনুসরণ করলেও সমস্যায় পড়তে সহজ। উদাহরণস্বরূপ, নিম্নলিখিতটি একটি সংকলন ত্রুটির কারণ এবং আপনাকে ব্যবহার করতে বলে -fpermissive:

#if __LP64__
typedef unsigned long word64;
#else
typedef unsigned long long word64;
#endif

// intel definition of rdrand64_step (http://software.intel.com/en-us/node/523864)
// extern int _rdrand64_step(unsigned __int64 *random_val);

// Try it:
word64 val;
int res = rdrand64_step(&val);

এটির ফলাফল:

error: invalid conversion from `word64* {aka long unsigned int*}' to `long long unsigned int*'

সুতরাং, এড়ানো LP64এবং এটিকে পরিবর্তন করুন:

typedef unsigned long long word64;

তারপরে, একটি 64-বিট আর্ম আইওটি গ্যাজেটে ঘুরে দেখুন যা নিওনকে সংজ্ঞায়িত করে LP64এবং ব্যবহার করে:

error: invalid conversion from `word64* {aka long long unsigned int*}' to `uint64_t*'
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.