আমি কীভাবে সি ++ এ বিগ-এন্ডিয়ান এবং লিটল এন্ডিয়ান মানগুলির মধ্যে রূপান্তর করব?


196

আমি কীভাবে সি ++ এ বিগ-এন্ডিয়ান এবং লিটল এন্ডিয়ান মানগুলির মধ্যে রূপান্তর করব?

সম্পাদনা: স্পষ্টতার জন্য, আমাকে বাইনারি ডেটা (ডাবল-স্পেসিচনের ফ্লোটিং পয়েন্ট ভ্যালু এবং 32-বিট এবং 64-বিট ইন্টিজার) এক সিপিইউ আর্কিটেকচার থেকে অন্যটিতে অনুবাদ করতে হবে। এটি নেটওয়ার্কিং জড়িত না, সুতরাং ntoh () এবং অনুরূপ ফাংশন এখানে কাজ করবে না।

সম্পাদনা # 2: আমি যে উত্তরটি গ্রহণ করেছি তা সরাসরি আমি যে টার্গেট করছি তার সংস্থাগুলির ক্ষেত্রে প্রযোজ্য (যার কারণে আমি এটি পছন্দ করেছি)। তবে এখানে আরও খুব ভাল, বহনযোগ্য উত্তর রয়েছে।


21
নেটওয়ার্কিংয়ের সাথে এর কিছু না করার পরেও এনটিও এইচটন ভাল কাজ করবে।
বেন কলিন্স

2
সাধারণভাবে এন্ডিয়নিয়াসের সাথে মোকাবিলা করার সর্বোত্তম উপায় হ'ল কোডটি সামান্য- এবং বড়-এন্ডিয়ান হোস্ট মেশিনে চালিত হয় তা নিশ্চিত করা। যদি এটি কাজ করে, আপনি সম্ভবত এটি সঠিকভাবে করেছেন। অনুমান যে আপনি x86 / এ আছেন তা অনুশীলন হিসাবে বিপজ্জনক।
jakobengblom2

10
hton ntoh যদি মেশিনটি বিগ-এন্ডিয়ান হয় তবে কাজ করবে না, কারণ প্রশ্নকারী প্রশ্নাতীতভাবে রূপান্তর সম্পাদন করতে চায় wants
ফাবস্প্রো

6
@ jakobengblom2 একমাত্র ব্যক্তি এটি উল্লেখ করেছেন। এই পৃষ্ঠাগুলির প্রায় সব উদাহরণই অন্তর্নিহিত অন্তর্নিহিততার অজ্ঞেয়বাদী না করে "অদলবদল" বাইটের মতো ধারণাগুলি ব্যবহার করে। আপনি যদি বাহ্যিক ফাইল ফর্ম্যাটগুলি (যার ভালভাবে সংজ্ঞা দেওয়া যায়) নিয়ে কাজ করে থাকেন তবে বহনযোগ্য ডেটা বাইট স্ট্রিম হিসাবে বিবেচনা করা এবং বাইট স্ট্রিমটি দেশীয় পূর্ণসংখ্যায় এবং থেকে রূপান্তর করা। আমি short swap(short x)কোডটি যতবারই দেখি ততক্ষণে ক্রিঞ্জ করি , কারণ আপনি যদি বিভিন্ন প্রান্তিকতা সহ কোনও প্ল্যাটফর্মে যান তবে এটি ভেঙে যাবে। ম্যাথিউ এম এর নীচে সঠিক উত্তর রয়েছে।
লাকাতা

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

উত্তর:


166

আপনি যদি ভিজ্যুয়াল সি ++ ব্যবহার করেন তবে নিম্নলিখিতগুলি করুন: আপনি অন্তর্নির্মিত অন্তর্ভুক্ত করুন এবং নিম্নলিখিত ফাংশনগুলিকে কল করুন:

16 বিট সংখ্যার জন্য:

unsigned short _byteswap_ushort(unsigned short value);

32 বিট সংখ্যার জন্য:

unsigned long _byteswap_ulong(unsigned long value);

Bit৪ বিট সংখ্যার জন্য:

unsigned __int64 _byteswap_uint64(unsigned __int64 value);

8 বিট সংখ্যা (অক্ষর) রূপান্তর করার দরকার নেই।

এছাড়াও এগুলি কেবল স্বাক্ষরযুক্ত মানগুলির জন্যই সংজ্ঞায়িত করা হয় তারা স্বাক্ষরিত পূর্ণসংখ্যার জন্যও কাজ করে।

ফ্লোটস এবং ডাবলসের ক্ষেত্রে এটি প্লেইন পূর্ণসংখ্যার মতোই আরও কঠিন কারণ এটি হোস্ট মেশিনে বাই-অর্ডারে থাকতে পারে বা নাও পারে। আপনি বিগ-এন্ডিয়ান মেশিনে এবং এর বিপরীতে লিটল এন্ডিয়ান ফ্লোট পেতে পারেন।

অন্যান্য সংকলকগুলিরও একই রকম অন্তঃসত্ত্বা রয়েছে।

ইন জিসিসি উদাহরণস্বরূপ আপনি সরাসরি কল করতে পারেন এখানে নথিভুক্ত কিছু builtins :

uint32_t __builtin_bswap32 (uint32_t x)
uint64_t __builtin_bswap64 (uint64_t x)

(কিছু অন্তর্ভুক্ত করার প্রয়োজন নেই)। আফাইক বিটস্ একই সাথে একটি জি সি সি-কেন্দ্রিক উপায়ে একই ফাংশনটি ঘোষণা করে।

16 বিট অদলবদল এটি একটি বিট-ঘোরানো।

আপনার নিজের ঘূর্ণায়নের পরিবর্তে ইন্টার্নিকগুলিতে কল করা আপনাকে সেরা পারফরম্যান্স এবং কোড ডেনসিটি বিটিডব্লিউ দেয় ..


11
জিসিসি সঙ্গে, আমি ব্যবহার করতে পারেন: #include <byteswap.h> int32_t bswap_32 (int32_t x) এর int64_t bswap_64 (int64_t x) এর
jmanning2k

5
__builtin_bswapXকেবলমাত্র জিসিসি-৪.৩ থেকে পাওয়া যাবে
ম্যাট জয়েনার

20
এরও কোন মূল্য নেই যে এই intrinsics / সবসময় / swap 'র বাইট, তারা মত নয় এর মূল্য htonl, htonsইত্যাদি আপনি আপনার পরিস্থিতির প্রসঙ্গ থেকে যখন জানতে আসলে বাইট অদলবদল করতে হবে।
ব্রায়ান ভ্যান্ডেনবার্গ

8
@ জেসন কারণ 8 বিট সংখ্যা বড় এবং সামান্য এন্ডিয়ানতে সমান। :-)
নীল পিপেনব্রিংক

2
@ ব্রায়ানভেনডেনবার্গ রাইট; ব্যবহার htonlএবং ntohlপ্রসঙ্গ সম্পর্কে উদ্বেজক কাজ করবে যখন প্ল্যাটফর্ম থেকে পোর্টেবল কোড লেখা এই ফাংশন সংজ্ঞায়িত এটা অদলবদল হলে সামান্য / মধ্য endian এবং উপর ছাড়া বড় endian এটি একটি নো-অপ হবেন। তবে, একটি স্ট্যান্ডার্ড ফাইল টাইপের ডিকোড করার সময় যা ছোট-এন্ডিয়ান (বিএমপি বলুন) হিসাবে সংজ্ঞায়িত করা হয়, তারপরেও একটি প্রসঙ্গটি জানতে হবে এবং কেবল htonlএবং এর উপর নির্ভর করতে পারে না ntohl
কিংবদন্তি

86

সহজভাবে করা:

#include <climits>

template <typename T>
T swap_endian(T u)
{
    static_assert (CHAR_BIT == 8, "CHAR_BIT != 8");

    union
    {
        T u;
        unsigned char u8[sizeof(T)];
    } source, dest;

    source.u = u;

    for (size_t k = 0; k < sizeof(T); k++)
        dest.u8[k] = source.u8[sizeof(T) - k - 1];

    return dest.u;
}

ব্যবহার: swap_endian<uint32_t>(42)


3
একটি upvote আছে। আমি কেবল uchars ব্যবহার করেছি, এবং 4 থেকে 1, 3 থেকে 2, 2 থেকে 3 এবং 1 থেকে 4 নির্ধারিত করেছি, তবে আপনার আকার বিভিন্ন হলে এটি আরও নমনীয়। 1 ম জেনারেল পেন্টিয়াম আইআইআরসি-তে 6 টি ঘড়ি। বিএসডাব্লুএপ 1 ঘন্টা, তবে প্ল্যাটফর্ম নির্দিষ্ট।

2
@ রকেটরোয়: হ্যাঁ, এবং গতি যদি কোনও সমস্যা হিসাবে দেখা দেয় তবে প্ল্যাটফর্ম- এবং টাইপ-নির্দিষ্ট ইন্ট্রিসিকের সাথে ওভারলোডগুলি লেখা খুব সহজ।
আলেকজান্দ্রি সি

3
@ মিহাইটোডর: অক্ষরের একটি অ্যারের মাধ্যমে টাইপকাস্টিংয়ের জন্য ইউনিয়নগুলির এই ব্যবহারটি স্ট্যান্ডার্ড দ্বারা স্পষ্টভাবে অনুমোদিত। যেমন দেখুন। এই প্রশ্ন
আলেকজান্দ্র সি।

4
@AlexandreC। না C ++ স্ট্যান্ডার্ডের মধ্যে - শুধুমাত্র সি C ++ (যা এই কোড আছে) এই কোড অনির্ধারিত আচরণ।
Rapptz

4
@ র্যাপ্টজ: ৩.১০ স্পষ্ট বলে মনে হচ্ছে: "যদি কোনও প্রোগ্রাম নীচের যেকোন একটির চেয়ে অন্য কোনও গ্লাভের মাধ্যমে কোনও অবজেক্টের সঞ্চিত মান অ্যাক্সেস করার চেষ্টা করে তবে আচরণটি পূর্বনির্ধারিত: [...] একটি চর বা স্বাক্ষরবিহীন চার্ট টাইপ। " সম্ভবত আমি এখানে কিছু মিস করছি, তবে এটি আমার কাছে পরিষ্কার ছিল যে চর পয়েন্টারগুলির মাধ্যমে যে কোনও ধরণের অ্যাক্সেসের স্পষ্টরূপে অনুমতি ছিল।
আলেকজান্দ্রি সি

75

রব পাইকের বাইট অর্ডার ফ্যালাসি থেকে :

আসুন ধরা যাক আপনার ডেটা স্ট্রিমটিতে সামান্য এন্ডিয়ান-এনকোডযুক্ত 32-বিট পূর্ণসংখ্যা রয়েছে। এটি কীভাবে নিষ্কাশন করবেন তা এখানে (স্বাক্ষরযুক্ত স্বাক্ষরিত বাইট ধরে):

i = (data[0]<<0) | (data[1]<<8) | (data[2]<<16) | (data[3]<<24);

যদি এটি বড়-এন্ডিয়ান হয় তবে এটি কীভাবে উত্তোলন করা যায় তা এখানে:

i = (data[3]<<0) | (data[2]<<8) | (data[1]<<16) | (data[0]<<24);

টিএল; ডিআর: আপনার প্ল্যাটফর্মের নেটিভ অর্ডার সম্পর্কে চিন্তা করবেন না, যেগুলি গণনা করা হচ্ছে সেগুলিই আপনার যে স্ট্রিমটি পড়ছে তার বাইট ক্রম এবং আপনি আশা করি এটির সংজ্ঞাটি ভালভাবে দেওয়া হয়েছে।

দ্রষ্টব্য: এটি মন্তব্যে মন্তব্য করা হয়েছিল যে অনুপস্থিত সুস্পষ্ট ধরণের রূপান্তর, এটি গুরুত্বপূর্ণ ছিল বা এর dataঅ্যারে হওয়া উচিত । ব্যবহার ( বা স্বাক্ষরিত থাকলে) এর ফলে কোনও পূর্ণসংখ্যায় উন্নীত হয় এবং সম্ভাব্যত 1 টি সাইন বিটে স্থানান্তরিত হয় যা ইউবি হয়।unsigned charuint8_tsigned charchardata[x]data[x] << 24


5
এটি দুর্দান্ত, তবে আমার কাছে মনে হয় এটি কেবল পূর্ণসংখ্যা এবং বৈকল্পিকের ক্ষেত্রে প্রযোজ্য। ফ্লোটস / ডাবলস নিয়ে কী করবেন?
ব্রেট

1
@ v.oddou: হ্যাঁ এবং না, মেমরি ম্যাপ করা ফাইলগুলি নেটওয়ার্ক ফ্রেমের তুলনায় হুবহু; আপনি যদি এগুলি সরাসরি না পড়তে স্বীকার করেন, তবে এগুলি সমস্ত বিষয় তাদের অন্তর্নিহিততা: যদি লিটল-এন্ডিয়ান হয় তবে প্রথম সূত্রটি ব্যবহার করুন, যদি এটি বড়-এন্ডিয়ান হয় তবে দ্বিতীয়টি ব্যবহার করুন। এর লবণের মূল্য নির্ধারণকারী কোনও সংকলক যদি অ্যানডিয়নেস মেলে তবে অপরিবর্তিত রূপান্তরগুলি অনুকূলিত করে তুলবে।
ম্যাথিউ এম।

2
@ মেসোস্কাক: হ্যাঁ, আমি আশা করি এটি কাজ করে, কারণ কেবল বাইটের ক্রম পরিবর্তন হয়, প্রতিটি বাইটের মধ্যে বিটের ক্রম নয়।
ম্যাথিউ এম।

3
একটি স্বল্পভাবে সম্পর্কিত নোটে, লিঙ্কযুক্ত পোস্টটি কিছু অপ্রীতিকর পড়ার মতো মনে হচ্ছে ... লোকটি ব্রেভিটিকে মূল্যবান বলে মনে হচ্ছে, তবুও তিনি সে সমস্ত খারাপ প্রোগ্রামার সম্পর্কে দীর্ঘ মন্তব্য লিখতে পছন্দ করেছেন যা প্রকৃতপক্ষে পরিবর্তনের পরিবর্তে তিনি প্রচ্ছন্নতার বিষয়ে আলোকিত নন, পরিস্থিতি ব্যাখ্যা করে এবং কেন তার সমাধান সর্বদা কার্যকর হয়।
বিজ্ঞাপন এন

1
আপনি এই পদ্ধতি ব্যবহার করেন, তাহলে নিশ্চিত করুন যে আপনি আপনার ডেটা (স্বাক্ষরবিহীন গৃহস্থালির কাজ *) কাস্ট করা
জোসেফ

51

আপনি যদি নেটওয়ার্ক / হোস্ট সামঞ্জস্যের উদ্দেশ্যে এটি করছেন তবে আপনার ব্যবহার করা উচিত:

ntohl() //Network to Host byte order (Long)
htonl() //Host to Network byte order (Long)

ntohs() //Network to Host byte order (Short)
htons() //Host to Network byte order (Short)

আপনি যদি অন্য কোনও কারণে এটি করছেন তবে এখানে উপস্থাপন করা বাইট_সপাপ সমাধানগুলির মধ্যে একটি ঠিকঠাক কাজ করবে।


2
নেটওয়ার্ক বাইট অর্ডার করা বড় ইন্ডিয়ান আমি বিশ্বাস করি। আপনি নেটওয়ার্ক কোড ব্যবহার না করলেও এই ফাংশনগুলি মনে রেখে এটি ব্যবহার করা যেতে পারে। তবে কোনও ভাসমান সংস্করণ নেই ntohf বা htonf
ম্যাট

2
ম্যাট এইচ। এটি কেবল বেশিরভাগ ক্ষেত্রেই সঠিক। সমস্ত কম্পিউটার সিস্টেমে স্বল্প-এন্ডিয়ান বাইট ক্রম নেই। আপনি যদি কাজ করে চলেছেন তবে কোনও মোটরোল্লা 68 কে, একটি পাওয়ারপিসি, বা অন্য কোনও বড়-এন্ডিয়ান আর্কিটেকচার এই ফাংশনগুলি বাইটগুলি মোটেও বদলাবে না কারণ তারা ইতিমধ্যে 'নেটওয়ার্ক বাইট ক্রমে রয়েছে।
ফ্রস্টি

2
দুর্ভাগ্যক্রমে, htonlএবং ntohlএকটি বড়-এন্ডিয়ান প্ল্যাটফর্মে সামান্য এন্ডিয়ান যেতে পারে না।
ব্রায়ান ভ্যান্ডেনবার্গ

2
@celtschk, বোঝা; যাইহোক, ওপি একটি বৃহত্তর পরিবেশের পরিবেশেও অন্তিমতা পরিবর্তন করার উপায় চায়।
ব্রায়ান ভ্যান্ডেনবার্গ

4
অনিবার্য প্রশ্ন থেকে বেরিয়ে আসার জন্য: বিই প্ল্যাটফর্মের জন্য এলই প্রয়োজন অনেকগুলি কারণ রয়েছে; বেশ কয়েকটি ফাইল ফর্ম্যাট (কিছু নাম লেখার জন্য বিএমপি, ফ্লি, পিসিএক্স, কিউটিএম, আরটিএফ, টগা) অল্প পরিমাণ এন্ডিয়ান মান ব্যবহার করে ... বা কমপক্ষে, বিন্যাসের কিছু সংস্করণ যে কোনও সময়ে একসাথে হয়েছিল।
ব্রায়ান ভ্যান্ডেনবার্গ

26

আমি এই পোস্ট থেকে কয়েকটি পরামর্শ নিয়েছি এবং এগুলি তৈরি করতে তাদের একত্র করেছি:

#include <boost/type_traits.hpp>
#include <boost/static_assert.hpp>
#include <boost/detail/endian.hpp>
#include <stdexcept>

enum endianness
{
    little_endian,
    big_endian,
    network_endian = big_endian,

    #if defined(BOOST_LITTLE_ENDIAN)
        host_endian = little_endian
    #elif defined(BOOST_BIG_ENDIAN)
        host_endian = big_endian
    #else
        #error "unable to determine system endianness"
    #endif
};

namespace detail {

template<typename T, size_t sz>
struct swap_bytes
{
    inline T operator()(T val)
    {
        throw std::out_of_range("data size");
    }
};

template<typename T>
struct swap_bytes<T, 1>
{
    inline T operator()(T val)
    {
        return val;
    }
};

template<typename T>
struct swap_bytes<T, 2>
{
    inline T operator()(T val)
    {
        return ((((val) >> 8) & 0xff) | (((val) & 0xff) << 8));
    }
};

template<typename T>
struct swap_bytes<T, 4>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff000000) >> 24) |
                (((val) & 0x00ff0000) >>  8) |
                (((val) & 0x0000ff00) <<  8) |
                (((val) & 0x000000ff) << 24));
    }
};

template<>
struct swap_bytes<float, 4>
{
    inline float operator()(float val)
    {
        uint32_t mem =swap_bytes<uint32_t, sizeof(uint32_t)>()(*(uint32_t*)&val);
        return *(float*)&mem;
    }
};

template<typename T>
struct swap_bytes<T, 8>
{
    inline T operator()(T val)
    {
        return ((((val) & 0xff00000000000000ull) >> 56) |
                (((val) & 0x00ff000000000000ull) >> 40) |
                (((val) & 0x0000ff0000000000ull) >> 24) |
                (((val) & 0x000000ff00000000ull) >> 8 ) |
                (((val) & 0x00000000ff000000ull) << 8 ) |
                (((val) & 0x0000000000ff0000ull) << 24) |
                (((val) & 0x000000000000ff00ull) << 40) |
                (((val) & 0x00000000000000ffull) << 56));
    }
};

template<>
struct swap_bytes<double, 8>
{
    inline double operator()(double val)
    {
        uint64_t mem =swap_bytes<uint64_t, sizeof(uint64_t)>()(*(uint64_t*)&val);
        return *(double*)&mem;
    }
};

template<endianness from, endianness to, class T>
struct do_byte_swap
{
    inline T operator()(T value)
    {
        return swap_bytes<T, sizeof(T)>()(value);
    }
};
// specialisations when attempting to swap to the same endianess
template<class T> struct do_byte_swap<little_endian, little_endian, T> { inline T operator()(T value) { return value; } };
template<class T> struct do_byte_swap<big_endian,    big_endian,    T> { inline T operator()(T value) { return value; } };

} // namespace detail

template<endianness from, endianness to, class T>
inline T byte_swap(T value)
{
    // ensure the data is only 1, 2, 4 or 8 bytes
    BOOST_STATIC_ASSERT(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
    // ensure we're only swapping arithmetic types
    BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

    return detail::do_byte_swap<from, to, T>()(value);
}

আপনার কাছে অন্তর্ভুক্ত করা রয়েছে <cstdint> অথবা <stdint.h> উদাহরণস্বরূপ, uint32_t জন্য
Ady

17

বিগ-এন্ডিয়ান থেকে লিটল এন্ডিয়ানে যাওয়ার পদ্ধতিটি লিটল-এন্ডিয়ান থেকে বিগ-এন্ডিয়ানে যাওয়ার সমান।

এখানে কয়েকটি উদাহরণ কোড রয়েছে:

void swapByteOrder(unsigned short& us)
{
    us = (us >> 8) |
         (us << 8);
}

void swapByteOrder(unsigned int& ui)
{
    ui = (ui >> 24) |
         ((ui<<8) & 0x00FF0000) |
         ((ui>>8) & 0x0000FF00) |
         (ui << 24);
}

void swapByteOrder(unsigned long long& ull)
{
    ull = (ull >> 56) |
          ((ull<<40) & 0x00FF000000000000) |
          ((ull<<24) & 0x0000FF0000000000) |
          ((ull<<8) & 0x000000FF00000000) |
          ((ull>>8) & 0x00000000FF000000) |
          ((ull>>24) & 0x0000000000FF0000) |
          ((ull>>40) & 0x000000000000FF00) |
          (ull << 56);
}

2
এখানে পোস্ট করা শেষ ফাংশনটি ভুল, এবং এতে সম্পাদনা করা উচিত: অকার্যকর swapByteOrder (স্বাক্ষরযুক্ত দীর্ঘ দীর্ঘ & ull) {ull = (ull >> 56) | ... (আল << 56); }
এরিক বারনেট

14
আমি মনে করি না যে বিটওয়াইস এবং (এবং) এর বিপরীতে লজিক্যাল-এবং (&&) ব্যবহার করা ঠিক হবে। সি ++ অনুমান অনুসারে, উভয় অপারেশনগুলি স্পষ্টভাবে বুলে রূপান্তরিত হয়, যা আপনি চান তা নয়।
ট্রেভর রবিনসন

16

একটা সমাবেশ নির্দেশ BSWAP নামক যে আপনার জন্য swap 'র কি করতে হবে, হয় অত্যন্ত দ্রুত । আপনি এটি সম্পর্কে এখানে পড়তে পারেন ।

ভিজ্যুয়াল স্টুডিও, বা আরও সুনির্দিষ্টভাবে ভিজ্যুয়াল সি ++ রানটাইম লাইব্রেরিতে এর জন্য প্ল্যাটফর্মের অন্তর্নিহিত রয়েছে, যাকে ডাকা হয় _byteswap_ushort(), _byteswap_ulong(), and _byteswap_int64()। অন্যান্য প্ল্যাটফর্মগুলির জন্য একই রকমের উপস্থিতি থাকা উচিত, তবে তাদের কী বলা হবে সে সম্পর্কে আমি অবগত নই।


এটি একটি দুর্দান্ত লিঙ্ক। এটি x86 এসেম্বলারের প্রতি আমার আগ্রহ পুনরুদ্ধার করে।
পিপি

1
বিএসডাব্লুএপির সময় ফলাফল এখানে উপস্থাপন করা হয়। gmplib.org/~tege/x86-timing.pdf ... এবং এখানে ... agner.org/optimize/in

12

আমরা টেমপ্লেটগুলি দিয়ে এটি করেছি। আপনি এরকম কিছু করতে পারেন:

// Specialization for 2-byte types.
template<>
inline void endian_byte_swapper< 2 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    ushort* p_dest = reinterpret_cast< ushort* >(dest);
    ushort const* const p_src = reinterpret_cast< ushort const* >(src);
    *p_dest = (*p_src >> 8) | (*p_src << 8);
}

// Specialization for 4-byte types.
template<>
inline void endian_byte_swapper< 4 >(char* dest, char const* src)
{
    // Use bit manipulations instead of accessing individual bytes from memory, much faster.
    uint* p_dest = reinterpret_cast< uint* >(dest);
    uint const* const p_src = reinterpret_cast< uint const* >(src);
    *p_dest = (*p_src >> 24) | ((*p_src & 0x00ff0000) >> 8) | ((*p_src & 0x0000ff00) << 8) | (*p_src << 24);
}

8

আপনি যদি বিভিন্ন প্ল্যাটফর্মের মধ্যে ডেটা স্থানান্তর করতে এটি করছেন তবে এনটিও এবং এইচটিও ফাংশনটি দেখুন।


7

আপনি সি তে একইভাবে:

short big = 0xdead;
short little = (((big & 0xff)<<8) | ((big & 0xff00)>>8));

আপনি স্বাক্ষরবিহীন অক্ষরগুলির একটি ভেক্টরও ঘোষণা করতে পারেন, এতে ইনপুট মানটি ম্যাকপি করে, বাইটগুলি অন্য ভেক্টরে বিপরীত করতে এবং বাইটগুলি মেমকি করে দিতে পারেন, তবে এটি বিট-টুইডলিংয়ের চেয়ে বেশি মাত্রার অর্ডার গ্রহণ করবে, বিশেষত -৪-বিট মান সহ।


7

বেশিরভাগ পসিক্স সিস্টেমে (এটি পসিক্স স্ট্যান্ডার্ডের মাধ্যমে নয়) এখানে এন্ডিয়ান হ'ল থাকে, যা আপনার সিস্টেমে কী এনকোডিং ব্যবহার করে তা নির্ধারণ করতে ব্যবহার করা যেতে পারে। সেখান থেকে এটি এরকম কিছু:

unsigned int change_endian(unsigned int x)
{
    unsigned char *ptr = (unsigned char *)&x;
    return (ptr[0] << 24) | (ptr[1] << 16) | (ptr[2] << 8) | ptr[3];
}

এটি অর্ডারটিকে অদলবদল করে (বড় এন্ডিয়ান থেকে সামান্য এন্ডিয়ান পর্যন্ত):

আপনার যদি 0xDEADBEEF নম্বর (0xEFBEADDE হিসাবে সঞ্চিত একটি সামান্য এডিয়ান সিস্টেমে) থাকে তবে পিটিআর [0] 0xEF, পিটিআর [1] 0xBE, ইত্যাদি হবে etc.

তবে আপনি যদি এটি নেটওয়ার্কিংয়ের জন্য ব্যবহার করতে চান, তবে হোস্টন অর্ডার থেকে নেটওয়ার্ক ক্রমে রূপান্তরিত করতে htons, htonl এবং htonll (এবং তাদের বিপরীতমুখী এনটিওএস, এনটিওএল এবং এনটোহল) সহায়ক হবে।


6
মজার বিষয় - ওপেনগ্রুপ . org/onlinepubs/9699919799/toc.htmপসিক্স স্ট্যান্ডার্ড কোনও শিরোনাম '<endian.h> mention উল্লেখ করে না `
জোনাথন লেফলার

1
htonlনেটওয়ার্কিংয়ের সাথে ইউস-কেসের কিছু আছে কিনা তা বিবেচনা না করেই আপনি এবং বন্ধুরা ব্যবহার করতে পারেন । নেটওয়ার্ক বাইট অর্ডার বড়-এন্ডিয়ান, সুতরাং কেবল সেই ফাংশনগুলি হোস্ট_ টো_বে এবং be_to_host হিসাবে বিবেচনা করুন। (যদিও আপনার হোস্ট_ টু_লে প্রয়োজন হলে সহায়তা করে না))
পিটার

5

মনে রাখবেন, কমপক্ষে উইন্ডোজের জন্য, htonl () তাদের অভ্যন্তরীণ অংশ _বিটসপ_লং () এর চেয়ে অনেক ধীর। প্রাক্তনটি ডাব্লুএল লাইব্রেরি কলটি ws2_32.dll এ কল করেন, দ্বিতীয়টি বিএসডাব্লুএপি সমাবেশের নির্দেশ ruction অতএব, আপনি যদি প্ল্যাটফর্ম নির্ভর কিছু কোড লিখছেন তবে গতির জন্য অন্তর্নিহিত ব্যবহার পছন্দ করুন:

#define htonl(x) _byteswap_ulong(x)

এটি পিপিএন ইমেজ প্রসেসিংয়ের জন্য বিশেষভাবে গুরুত্বপূর্ণ হতে পারে যেখানে বিগ এন্ডিয়ানে সমস্ত পূর্ণসংখ্যা সংরক্ষণ করা হয় "আপনি যদি প্রস্তুত না হন তবে সাধারণ উইন্ডোজ প্রোগ্রামগুলি ধীরে ধীরে" htonl () ব্যবহার করতে পারেন ... "explanation


4

বেশিরভাগ প্ল্যাটফর্মে একটি সিস্টেম শিরোলেখ ফাইল থাকে যা দক্ষ বাইটসপ ফাংশন সরবরাহ করে। লিনাক্স এ এটি আছে <endian.h>। আপনি এটি সি ++ এ সুন্দরভাবে গুটিয়ে রাখতে পারেন:

#include <iostream>

#include <endian.h>

template<size_t N> struct SizeT {};

#define BYTESWAPS(bits) \
template<class T> inline T htobe(T t, SizeT<bits / 8>) { return htobe ## bits(t); } \
template<class T> inline T htole(T t, SizeT<bits / 8>) { return htole ## bits(t); } \
template<class T> inline T betoh(T t, SizeT<bits / 8>) { return be ## bits ## toh(t); } \
template<class T> inline T letoh(T t, SizeT<bits / 8>) { return le ## bits ## toh(t); }

BYTESWAPS(16)
BYTESWAPS(32)
BYTESWAPS(64)

#undef BYTESWAPS

template<class T> inline T htobe(T t) { return htobe(t, SizeT<sizeof t>()); }
template<class T> inline T htole(T t) { return htole(t, SizeT<sizeof t>()); }
template<class T> inline T betoh(T t) { return betoh(t, SizeT<sizeof t>()); }
template<class T> inline T letoh(T t) { return letoh(t, SizeT<sizeof t>()); }

int main()
{
    std::cout << std::hex;
    std::cout << htobe(static_cast<unsigned short>(0xfeca)) << '\n';
    std::cout << htobe(0xafbeadde) << '\n';

    // Use ULL suffix to specify integer constant as unsigned long long 
    std::cout << htobe(0xfecaefbeafdeedfeULL) << '\n';
}

আউটপুট:

cafe
deadbeaf
feeddeafbeefcafe

পরিবর্তন: # নির্ধারণ বিটেস্পস (বিটস) \ টেমপ্লেট <ক্লাস টি> ইনলাইন টি টিটোব (টি টি, সাইজটি <বিটস / 8>) {রিটার্ন টোটো ## বিটস (টি); \ \ টেমপ্লেট <ক্লাস টি> ইনলাইন টি হোমোল (টি টি, সাইজটি <বিটস / 8>) {রিটার্ন হটোল ## বিট (টি); \ \ টেমপ্লেট <ক্লাস টি> ইনলাইন টি বেটোহ (টি টি, সাইজটি <বিটস / 8>) {ফিরে আসুন ## বিট ## তো (টি); \ \ টেমপ্লেট <ক্লাস টি> ইনলাইন টি লেটো (টি টি, সাইজটি <বিট / 8>) {রিটার্ন লে ## বিট ## তো (টি); }
ldav1s

ধন্যবাদ, বেটো () এবং লেটো () পরীক্ষা করতে ভুলে গেছি।
ম্যাক্সিম এগারুশকিন

4

আমি এটি পছন্দ করি, কেবল স্টাইলের জন্য :-)

long swap(long i) {
    char *c = (char *) &i;
    return * (long *) (char[]) {c[3], c[2], c[1], c[0] };
}

char[]'ত্রুটি: অসম্পূর্ণ প্রকারের অনুমতি নেই' বলার সময় আমি একটি ত্রুটি পেয়েছি
পোর্টল্যান্ড রানার

4

সিরিয়াসলি ... আমি বুঝতে পারছি না যে সমস্ত সমাধান কেন এত জটিল ! সবচেয়ে সহজ, সবচেয়ে সাধারণ টেম্পলেট ফাংশন সম্পর্কে যা কোনও অপারেটিং সিস্টেমে যে কোনও পরিস্থিতিতে যে কোনও আকারের যে কোনও ধরণের অদলবদল করে ????

template <typename T>
void SwapEnd(T& var)
{
    static_assert(std::is_pod<T>::value, "Type must be POD type for safety");
    std::array<char, sizeof(T)> varArray;
    std::memcpy(varArray.data(), &var, sizeof(T));
    for(int i = 0; i < static_cast<int>(sizeof(var)/2); i++)
        std::swap(varArray[sizeof(var) - 1 - i],varArray[i]);
    std::memcpy(&var, varArray.data(), sizeof(T));
}

এটি এক সাথে সি এবং সি ++ এর যাদু শক্তি! কেবল অক্ষর অনুসারে মূল পরিবর্তনশীল চরিত্রটি অদলবদল করুন।

পয়েন্ট 1 : কোনও অপারেটর নেই: মনে রাখবেন যে আমি সাধারণ অ্যাসাইনমেন্ট অপারেটর "=" ব্যবহার করি নি কারণ কিছু জিনিস যখন গণ্ডগোল হবে তখন কপিরাইট কনস্ট্রাক্টর (বা অ্যাসাইনমেন্ট অপারেটর) কাজ করবে না। অতএব, চরের ভিত্তিতে এগুলি অনুলিপি করা আরও নির্ভরযোগ্য।

পয়েন্ট 2 : প্রান্তিককরণের বিষয়ে সচেতন থাকুন: লক্ষ্য করুন যে আমরা একটি অ্যারেতে এবং তার থেকে অনুলিপি করছি, যা করা সঠিক কাজ কারণ সি ++ সংকলক গ্যারান্টি দেয় না যে আমরা স্বাক্ষরবিহীন মেমরি অ্যাক্সেস করতে পারি (এই উত্তরটি এর মূল থেকে আপডেট হয়েছিল এই জন্য ফর্ম)। উদাহরণস্বরূপ, আপনি যদি বরাদ্দ করেন তবে uint64_tআপনার সংকলক গ্যারান্টি দিতে পারে না যে আপনি এটির তৃতীয় বাইটটি অ্যাক্সেস করতে পারেন uint8_t। অতএব, সঠিক জিনিসটি হ'ল এটি একটি চরের অ্যারে অনুলিপি করা, এটি অদলবদল করা, তারপরে এটি আবার অনুলিপি (তাই না reinterpret_cast)। খেয়াল করুন যে সংকলকগুলি reinterpret_castপ্রান্তিককরণ নির্বিশেষে পৃথক বাইটগুলি অ্যাক্সেস করতে সক্ষম হলে আপনি কী করেছিলেন তা রূপান্তর করতে বেশিরভাগই যথেষ্ট স্মার্ট ।

এই ফাংশনটি ব্যবহার করতে :

double x = 5;
SwapEnd(x);

এবং এখন xশেষের দিক থেকে আলাদা।


2
এই জন্য যে কোন জায়গায় কাজ করবে, কিন্তু সমাবেশ ocde উত্পাদিত প্রায়ই দরুণ পর্যাপ্ত হবে: আমার প্রশ্ন দেখতে পাবেন stackoverflow.com/questions/36657895/...
j_kubik

আপনি কি এর জন্য একটি বাফার বরাদ্দ করতে new/ ব্যবহার করেন delete?!?! sizeof(var)একটি সংকলন-সময় ধ্রুবক, তাই আপনি করতে পারেন char varSwapped[sizeof(var)]। অথবা আপনি char *p = reinterpret_cast<char*>(&var)জায়গায় জায়গায় বদল করতে পারেন ।
পিটার

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

এই উত্তরটি ভুল-এন্ডিয়ান ডেটাতে কন্সট্রাক্টর এবং ওভারলোডেড অপারেটরদের সম্পর্কে সতর্ক থাকার সম্পর্কে কিছু দরকারী পয়েন্ট তৈরি করে, তাই কোডটি ভয়াবহ না হলে আমার ডাউনভোটটি সরিয়ে ফেলতে পেরে আমি খুশি হব, এবং এমন একটি ভাল সংকলক একটি বিস্যাপের মধ্যে সংকলন করতে পারে is নির্দেশ. এছাড়াও, আমি এ এর for(size_t i = 0 ; i < sizeof(var) ; i++)পরিবর্তে ব্যবহার করার পরামর্শ দেব static_cast<long>। (বা প্রকৃতপক্ষে, ইন-প্লেস অদলবদু আরোহী এবং অবতরণ ব্যবহার করবে char*যাতে যেভাবে যায় away
পিটার

উদাহরণস্বরূপ বিপরীতে স্ট্যান্ড :: সোয়াপ ব্যবহার করে মার্ক রেনসমের উত্তর দেখুন ।
পিটার

3

আমার কাছে এই কোডটি রয়েছে যা আমাকে HOST_ENDIAN_ORDER (এটি যাই হোক না কেন) থেকে LITTLE_ENDIAN_ORDER বা BIG_ENDIAN_ORDER এ রূপান্তর করতে দেয়। আমি একটি টেমপ্লেট ব্যবহার করি, তাই যদি আমি HOST_ENDIAN_ORDER থেকে LITTLE_ENDIAN_ORDER তে রূপান্তরিত করার চেষ্টা করি এবং আমার সংকলনের জন্য তারা মেশিনের জন্য একই হয় তবে কোনও কোড উত্পন্ন হবে না।

কিছু মন্তব্য সহ কোড এখানে:

// We define some constant for little, big and host endianess. Here I use 
// BOOST_LITTLE_ENDIAN/BOOST_BIG_ENDIAN to check the host indianess. If you
// don't want to use boost you will have to modify this part a bit.
enum EEndian
{
  LITTLE_ENDIAN_ORDER,
  BIG_ENDIAN_ORDER,
#if defined(BOOST_LITTLE_ENDIAN)
  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
#elif defined(BOOST_BIG_ENDIAN)
  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
#else
#error "Impossible de determiner l'indianness du systeme cible."
#endif
};

// this function swap the bytes of values given it's size as a template
// parameter (could sizeof be used?).
template <class T, unsigned int size>
inline T SwapBytes(T value)
{
  union
  {
     T value;
     char bytes[size];
  } in, out;

  in.value = value;

  for (unsigned int i = 0; i < size / 2; ++i)
  {
     out.bytes[i] = in.bytes[size - 1 - i];
     out.bytes[size - 1 - i] = in.bytes[i];
  }

  return out.value;
}

// Here is the function you will use. Again there is two compile-time assertion
// that use the boost librarie. You could probably comment them out, but if you
// do be cautious not to use this function for anything else than integers
// types. This function need to be calles like this :
//
//     int x = someValue;
//     int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
//
template<EEndian from, EEndian to, class T>
inline T EndianSwapBytes(T value)
{
  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
  BOOST_STATIC_ASSERT(sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);

  // A : La donnée à swapper est d'un type arithmetic
  BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);

  // Si from et to sont du même type on ne swap pas.
  if (from == to)
     return value;

  return SwapBytes<T, sizeof(T)>(value);
}

3

যদি একটি বড়-এন্ডিয়ান 32-বিট স্বাক্ষরযুক্ত পূর্ণসংখ্যা 0xAABBCCDD এর মতো দেখতে 2828434397 এর সমান হয়, তবে সেই একই 32-বিট স্বাক্ষরযুক্ত পূর্ণসংখ্যা 0xDDCCBBAA এর মতো দেখায় সামান্য এন্ডিয়ান প্রসেসরের উপরও এটি 2864434397 এর সমান।

যদি একটি বড়-এন্ডিয়ান 16-বিট স্বাক্ষরযুক্ত শর্ট 0xAABB এর মতো লাগে যা 43707 এর সমান হয়, তবে সেই একই 16-বিট স্বাক্ষরযুক্ত শর্টটি অল্প-এন্ডিয়ান প্রসেসরে 0xBBAA এর মতো লাগে যা 43707 এর সমান।

লিট-এন্ডিয়ান থেকে বিগ-এন্ডিয়ান এবং বিপরীত দিকে বাইটগুলি অদলবদল করার জন্য এখানে কয়েকটি কার্যকরী # ডিফাইন ফাংশন রয়েছে ->

// can be used for short, unsigned short, word, unsigned word (2-byte types)
#define BYTESWAP16(n) (((n&0xFF00)>>8)|((n&0x00FF)<<8))

// can be used for int or unsigned int or float (4-byte types)
#define BYTESWAP32(n) ((BYTESWAP16((n&0xFFFF0000)>>16))|((BYTESWAP16(n&0x0000FFFF))<<16))

// can be used for unsigned long long or double (8-byte types)
#define BYTESWAP64(n) ((BYTESWAP32((n&0xFFFFFFFF00000000)>>32))|((BYTESWAP32(n&0x00000000FFFFFFFF))<<32))

2

এখানে একটি সাধারণ সংস্করণটি আমি স্থানে একটি মান অদলবদলের জন্য আমার মাথার উপরের অংশটি নিয়ে এলাম। পারফরম্যান্স সমস্যা হলে অন্যান্য পরামর্শগুলি আরও ভাল।

 template<typename T>
    void ByteSwap(T * p)
    {
        for (int i = 0;  i < sizeof(T)/2;  ++i)
            std::swap(((char *)p)[i], ((char *)p)[sizeof(T)-1-i]);
    }

দাবি অস্বীকার: আমি এটি সংকলন করার বা এটি পরীক্ষা করার চেষ্টা করিনি এখনও।


2

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

x = ((x & 0x00000000ffffffff) << 32) ^ ((x >> 32) & 0x00000000ffffffff);
x = ((x & 0x0000ffff0000ffff) << 16) ^ ((x >> 16) & 0x0000ffff0000ffff);
x = ((x & 0x00ff00ff00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff00ff00ff);

কম্পাইলার উচিত অতিরিক্ত বিট-মাস্কিং অপারেশন (আমি তাদের মধ্যে বাম প্যাটার্ন হাইলাইট করতে) পরিষ্কার, কিন্তু যদি এটা আছে না প্রথম লাইন এই ভাবে পুনর্লিখন করতে পারেন:

x = ( x                       << 32) ^  (x >> 32);

এটি সাধারণত বেশিরভাগ আর্কিটেকচারের একক ঘোরানো নির্দেশনায় সরল করা উচিত (পুরো অপারেশনটি সম্ভবত একটি নির্দেশনা তা উপেক্ষা করে)।

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

uint64_t k = 0x00000000ffffffff; /* compiler should know a trick for this */
x = ((x & k) << 32) ^ ((x >> 32) & k);
k ^= k << 16;
x = ((x & k) << 16) ^ ((x >> 16) & k);
k ^= k << 8;
x = ((x & k) <<  8) ^ ((x >>  8) & k);

আপনি যদি চান, আপনি এটি লুপ হিসাবে লিখতে পারেন। এটি দক্ষ হবে না, তবে কেবল মজাদার জন্য:

int i = sizeof(x) * CHAR_BIT / 2;
uintmax_t k = (1 << i) - 1;
while (i >= 8)
{
    x = ((x & k) << i) ^ ((x >> i) & k);
    i >>= 1;
    k ^= k << i;
}

এবং সম্পূর্ণতার জন্য, এখানে প্রথম ফর্মটির সরলীকৃত 32-বিট সংস্করণ দেওয়া হয়েছে:

x = ( x               << 16) ^  (x >> 16);
x = ((x & 0x00ff00ff) <<  8) ^ ((x >>  8) & 0x00ff00ff);

2

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

template<typename T> inline static T swapByteOrder(const T& val) {
    int totalBytes = sizeof(val);
    T swapped = (T) 0;
    for (int i = 0; i < totalBytes; ++i) {
        swapped |= (val >> (8*(totalBytes-i-1)) & 0xFF) << (8*i);
    }
    return swapped;
}

2

আমি সত্যিই অবাক হয়েছি কেউ htobeXX এবং betohXX ফাংশন উল্লেখ করেনি। এগুলি এডিয়ান হ'লে সংজ্ঞায়িত করা হয় এবং নেটওয়ার্ক ফাংশন এইচটিএনএক্সএক্সের সাথে খুব মিল।


2

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

#define uint32_t unsigned 
#define uint16_t unsigned short

#define swap16(x) ((((uint16_t)(x) & 0x00ff)<<8)| \
(((uint16_t)(x) & 0xff00)>>8))

#define swap32(x) ((((uint32_t)(x) & 0x000000ff)<<24)| \
(((uint32_t)(x) & 0x0000ff00)<<8)| \
(((uint32_t)(x) & 0x00ff0000)>>8)| \
(((uint32_t)(x) & 0xff000000)>>24))

1

আমি সম্প্রতি সি তে এটি করার জন্য একটি ম্যাক্রো লিখেছি, তবে এটি সি ++ তে সমানভাবে বৈধ:

#define REVERSE_BYTES(...) do for(size_t REVERSE_BYTES=0; REVERSE_BYTES<sizeof(__VA_ARGS__)>>1; ++REVERSE_BYTES)\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES],\
    ((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES] ^= ((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES];\
while(0)

এটি যে কোনও ধরণের গ্রহণ করে এবং পাস আর্গুমেন্টে বাইটগুলি বিপরীত করে। ব্যবহারের উদাহরণ:

int main(){
    unsigned long long x = 0xABCDEF0123456789;
    printf("Before: %llX\n",x);
    REVERSE_BYTES(x);
    printf("After : %llX\n",x);

    char c[7]="nametag";
    printf("Before: %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
    REVERSE_BYTES(c);
    printf("After : %c%c%c%c%c%c%c\n",c[0],c[1],c[2],c[3],c[4],c[5],c[6]);
}

কোন মুদ্রণ:

Before: ABCDEF0123456789
After : 8967452301EFCDAB
Before: nametag
After : gateman

উপরেরটি নিখুঁতভাবে অনুলিপি / পেস্ট-সক্ষম, তবে এখানে অনেক কিছু চলছে, সুতরাং আমি কীভাবে এটি টুকরো টুকরো করে কাজ করব তা ভেঙে দেব:

প্রথম উল্লেখযোগ্য জিনিসটি হ'ল পুরো ম্যাক্রো একটি do while(0)ব্লকে আবদ্ধ । ম্যাক্রোর পরে সাধারণ সেমিকোলন ব্যবহারের অনুমতি দেওয়ার জন্য এটি একটি সাধারণ প্রতিমা i

এরপরে লুপের কাউন্টার REVERSE_BYTESহিসাবে পরিচিত একটি ভেরিয়েবলের ব্যবহার for। ম্যাক্রোর নামটি নিজেই একটি পরিবর্তনশীল নাম হিসাবে ব্যবহৃত হয় তা নিশ্চিত করার জন্য এটি ম্যাক্রো যেখানে ব্যবহার করা হয়েছে সেখানে অন্য কোনও চিহ্নের সাথে সংঘর্ষ না ঘটায় তা নিশ্চিত হতে পারে। যেহেতু নামটি ম্যাক্রোর সম্প্রসারণের মধ্যে ব্যবহার করা হচ্ছে, এখানে পরিবর্তনশীল নাম হিসাবে ব্যবহার করার পরে এটি আর প্রসারিত হবে না।

মধ্যে forলুপ, দুই বাইট উল্লেখ করা হচ্ছে এবং হয় XOR যাও অদলবদল (তাই একটি অস্থায়ী পরিবর্তনশীল নাম প্রয়োজন হয় না):

((unsigned char*)&(__VA_ARGS__))[REVERSE_BYTES]
((unsigned char*)&(__VA_ARGS__))[sizeof(__VA_ARGS__)-1-REVERSE_BYTES]

__VA_ARGS__ম্যাক্রোকে যা কিছু দেওয়া হয়েছিল তা উপস্থাপন করে এবং যা পাস হতে পারে তার নমনীয়তা বাড়ানোর জন্য ব্যবহৃত হয় (তবে অনেক বেশি নয়)। এরপরে এই আর্গুমেন্টের ঠিকানাটি নেওয়া হয় এবং unsigned charঅ্যারে []সাবস্ক্রিপশনের মাধ্যমে এর বাইটগুলি অদলবদলের অনুমতি দেওয়ার জন্য একটি পয়েন্টারে কাস্ট করা হয় ।

চূড়ান্ত অদ্ভুত পয়েন্ট হ'ল {}বন্ধনীগুলির অভাব । এগুলি প্রয়োজনীয় নয় কারণ প্রতিটি অদলবদলের সমস্ত পদক্ষেপ কমা অপারেটরের সাথে যুক্ত হয়ে তাদের একটি বিবৃতি তৈরি করে।

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


এটি কোথাও কোথাও খুঁজে পেয়েছি। হ্যাক আমার থেকে বিভ্রান্ত। ব্যাখ্যার জন্য ধন্যবাদ. তবে কেন ব্যবহার __VA_ARGS__?
asr9

0

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

__declspec(naked) uint32_t EndianSwap(uint32 value)
{
    __asm
    {
        mov eax, dword ptr[esp + 4]
        bswap eax
        ret
    }
}

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

unsigned long _byteswap_ulong(unsigned long value);

১ x বিট করা ঠিক তত সহজ, আপনি xchg আল, আহ ব্যবহার করতে চান। bswap শুধুমাত্র 32-বিট রেজিস্টারে কাজ করে।

-৪-বিটটি আরও জটিল, তবে অতিরিক্ত নয়। লুপ এবং টেম্পলেট ইত্যাদির উপরের উদাহরণগুলির তুলনায় অনেক ভাল better

এখানে কিছু ক্যাভেট রয়েছে ... প্রথমে bswap কেবল 80x486 সিপিইউ এবং তারপরের উপর উপলব্ধ on কেউ কি এটি 386 এ চালানোর পরিকল্পনা করছেন ?!? যদি তা হয় তবে আপনি এরপরেও bswap প্রতিস্থাপন করতে পারেন ...

mov ebx, eax
shr ebx, 16
xchg bl, bh
xchg al, ah
shl eax, 16
or eax, ebx

এছাড়াও ইনলাইন সমাবেশ কেবলমাত্র ভিজ্যুয়াল স্টুডিওতে x86 কোডে উপলব্ধ। একটি নগ্ন ফাংশন রেখাযুক্ত করা যাবে না এবং এটি x 64 বিল্ডগুলিতেও উপলব্ধ নয়। আমি উদাহরণস্বরূপ, আপনি সংকলক অভ্যন্তরীণ ব্যবহার করতে হবে।


1
_byteswap_ulongএবং _uint64(যেমন স্বীকৃত উত্তরে) উভয়ই bswapনির্দেশনাটি ব্যবহার করতে সংকলন করে । আমি অবাক হলেও জানতে আগ্রহী হব যে এই এসএমটি এত দ্রুত কিনা এটি কেবল প্রলোগ / উপসাগর বাদ দেয় - আপনি কি এটি বেঞ্চমার্ক করেছেন?
ZachB

@stdcall প্রশ্নটি কোনও বহনযোগ্য সমাধানের জন্য জিজ্ঞাসা করে না বা এমনকি প্ল্যাটফর্ম সম্পর্কে কিছু উল্লেখও করে নি। আমার উত্তর যেমনটি বলেছে, উপরেরটি এন্ডিয়ান অদলবদলের দ্রুততম উপায় সম্পর্কে। অবশ্যই, আপনি যদি এটি একটি নন-এক্স 8686 প্ল্যাটফর্মে লিখছেন তবে এটি কার্যকর হবে না, তবে আমি যেমনটি উল্লেখ করেছি যে, আপনি যদি তখনই সংকলক অন্তর্ভুক্তিতে সীমাবদ্ধ থাকেন, যদি আপনার সংকলক এমনকি তাদের সমর্থন করে।
ওয়েল্ড

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

2
সম্ভবত। তবে মনে রাখবেন যে সংখ্যার অ্যারেটি অদলবদলের সাধারণ ক্ষেত্রে, অন্যান্য উত্তরে আলোচিত সংকলক অন্তর্নিহিতগুলি এসএসই / এভিএক্স এক্সটেনশনগুলি ব্যবহার করবে এবং পিএসএইচইউএফবি নির্গত করবে, যা বিএসডাব্লুএপকে ছাড়িয়ে যাবে। Wm.ite.pl/articles/revers-array-of-bytes.html
ZachB

প্ল্যাটফর্ম-নির্দিষ্ট সমাধান পোস্ট করার পক্ষে এটি খারাপ ফর্ম আইএমএইচও, যখন ওপি নির্দিষ্ট করে না যে তাদের কেবলমাত্র x86 এর সমাধান প্রয়োজন। এবং অন্যান্য সমাধানগুলি অস্বীকার করার জন্য, যখন আপনার অনেকগুলি বহুল ব্যবহৃত ওএস যেমন আইওএস এবং অ্যান্ড্রয়েড (যা এআরএম বা এমআইপিএস সিপিইউ ব্যবহার করে) তে
ব্যবহারযোগ্য নয়

0

অপ্টিমাইজার-বান্ধব আন-সাইন ইন-প্লেস এন্ডিয়ান অ্যাকসেসরগুলি বাস্তবায়নের জন্য পোর্টেবল কৌশল। তারা প্রতিটি সংকলক, প্রতিটি সীমা অ্যালাইনমেন্ট এবং প্রতিটি বাইট ক্রম নিয়ে কাজ করে। এই স্বাক্ষরবিহীন রুটিনগুলি দেশীয় এন্ডিয়ান এবং প্রান্তিককরণের উপর নির্ভর করে পরিপূরক বা মোটা করা হয়। আংশিক তালিকাভুক্তি তবে আপনি ধারণা পাবেন। বিও * হ'ল দেশীয় বাইট ক্রমের ভিত্তিতে স্থির মান values

uint32_t sw_get_uint32_1234(pu32)
uint32_1234 *pu32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32_1234[0] = (*pu32)[BO32_0];
  bou32.u32_1234[1] = (*pu32)[BO32_1];
  bou32.u32_1234[2] = (*pu32)[BO32_2];
  bou32.u32_1234[3] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_1234(pu32, u32)
uint32_1234 *pu32;
uint32_t u32;
{
  union {
    uint32_1234 u32_1234;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_1234[0];
  (*pu32)[BO32_1] = bou32.u32_1234[1];
  (*pu32)[BO32_2] = bou32.u32_1234[2];
  (*pu32)[BO32_3] = bou32.u32_1234[3];
}

#if HAS_SW_INT64
int64 sw_get_int64_12345678(pi64)
int64_12345678 *pi64;
{
  union {
    int64_12345678 i64_12345678;
    int64 i64;
  } boi64;
  boi64.i64_12345678[0] = (*pi64)[BO64_0];
  boi64.i64_12345678[1] = (*pi64)[BO64_1];
  boi64.i64_12345678[2] = (*pi64)[BO64_2];
  boi64.i64_12345678[3] = (*pi64)[BO64_3];
  boi64.i64_12345678[4] = (*pi64)[BO64_4];
  boi64.i64_12345678[5] = (*pi64)[BO64_5];
  boi64.i64_12345678[6] = (*pi64)[BO64_6];
  boi64.i64_12345678[7] = (*pi64)[BO64_7];
  return(boi64.i64);
}
#endif

int32_t sw_get_int32_3412(pi32)
int32_3412 *pi32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32_3412[2] = (*pi32)[BO32_0];
  boi32.i32_3412[3] = (*pi32)[BO32_1];
  boi32.i32_3412[0] = (*pi32)[BO32_2];
  boi32.i32_3412[1] = (*pi32)[BO32_3];
  return(boi32.i32);
}

void sw_set_int32_3412(pi32, i32)
int32_3412 *pi32;
int32_t i32;
{
  union {
    int32_3412 i32_3412;
    int32_t i32;
  } boi32;
  boi32.i32 = i32;
  (*pi32)[BO32_0] = boi32.i32_3412[2];
  (*pi32)[BO32_1] = boi32.i32_3412[3];
  (*pi32)[BO32_2] = boi32.i32_3412[0];
  (*pi32)[BO32_3] = boi32.i32_3412[1];
}

uint32_t sw_get_uint32_3412(pu32)
uint32_3412 *pu32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32_3412[2] = (*pu32)[BO32_0];
  bou32.u32_3412[3] = (*pu32)[BO32_1];
  bou32.u32_3412[0] = (*pu32)[BO32_2];
  bou32.u32_3412[1] = (*pu32)[BO32_3];
  return(bou32.u32);
}

void sw_set_uint32_3412(pu32, u32)
uint32_3412 *pu32;
uint32_t u32;
{
  union {
    uint32_3412 u32_3412;
    uint32_t u32;
  } bou32;
  bou32.u32 = u32;
  (*pu32)[BO32_0] = bou32.u32_3412[2];
  (*pu32)[BO32_1] = bou32.u32_3412[3];
  (*pu32)[BO32_2] = bou32.u32_3412[0];
  (*pu32)[BO32_3] = bou32.u32_3412[1];
}

float sw_get_float_1234(pf)
float_1234 *pf;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f_1234[0] = (*pf)[BO32_0];
  bof.f_1234[1] = (*pf)[BO32_1];
  bof.f_1234[2] = (*pf)[BO32_2];
  bof.f_1234[3] = (*pf)[BO32_3];
  return(bof.f);
}

void sw_set_float_1234(pf, f)
float_1234 *pf;
float f;
{
  union {
    float_1234 f_1234;
    float f;
  } bof;
  bof.f = (float)f;
  (*pf)[BO32_0] = bof.f_1234[0];
  (*pf)[BO32_1] = bof.f_1234[1];
  (*pf)[BO32_2] = bof.f_1234[2];
  (*pf)[BO32_3] = bof.f_1234[3];
}

double sw_get_double_12345678(pd)
double_12345678 *pd;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d_12345678[0] = (*pd)[BO64_0];
  bod.d_12345678[1] = (*pd)[BO64_1];
  bod.d_12345678[2] = (*pd)[BO64_2];
  bod.d_12345678[3] = (*pd)[BO64_3];
  bod.d_12345678[4] = (*pd)[BO64_4];
  bod.d_12345678[5] = (*pd)[BO64_5];
  bod.d_12345678[6] = (*pd)[BO64_6];
  bod.d_12345678[7] = (*pd)[BO64_7];
  return(bod.d);
}

void sw_set_double_12345678(pd, d)
double_12345678 *pd;
double d;
{
  union {
    double_12345678 d_12345678;
    double d;
  } bod;
  bod.d = d;
  (*pd)[BO64_0] = bod.d_12345678[0];
  (*pd)[BO64_1] = bod.d_12345678[1];
  (*pd)[BO64_2] = bod.d_12345678[2];
  (*pd)[BO64_3] = bod.d_12345678[3];
  (*pd)[BO64_4] = bod.d_12345678[4];
  (*pd)[BO64_5] = bod.d_12345678[5];
  (*pd)[BO64_6] = bod.d_12345678[6];
  (*pd)[BO64_7] = bod.d_12345678[7];
}

এই টাইপডিফগুলির অ্যাক্সেসরগুলির সাথে ব্যবহার না করা হলে সংকলক ত্রুটিগুলি বাড়ানোর সুবিধা রয়েছে, যাতে ভুলে যাওয়া অ্যাক্সেসর বাগগুলি প্রশমিত করা যায়।

typedef char int8_1[1], uint8_1[1];

typedef char int16_12[2], uint16_12[2]; /* little endian */
typedef char int16_21[2], uint16_21[2]; /* big endian */

typedef char int24_321[3], uint24_321[3]; /* Alpha Micro, PDP-11 */

typedef char int32_1234[4], uint32_1234[4]; /* little endian */
typedef char int32_3412[4], uint32_3412[4]; /* Alpha Micro, PDP-11 */
typedef char int32_4321[4], uint32_4321[4]; /* big endian */

typedef char int64_12345678[8], uint64_12345678[8]; /* little endian */
typedef char int64_34128756[8], uint64_34128756[8]; /* Alpha Micro, PDP-11 */
typedef char int64_87654321[8], uint64_87654321[8]; /* big endian */

typedef char float_1234[4]; /* little endian */
typedef char float_3412[4]; /* Alpha Micro, PDP-11 */
typedef char float_4321[4]; /* big endian */

typedef char double_12345678[8]; /* little endian */
typedef char double_78563412[8]; /* Alpha Micro? */
typedef char double_87654321[8]; /* big endian */

2
এই প্রশ্নের জন্য, সি ++ ট্যাগ একটি পার্থক্য করে। সি ++ এবং ইউনিয়নের কারণে প্রচুর অপরিজ্ঞাত আচরণ রয়েছে।
jww

0

আইইইই 754 64 বিট ফর্ম্যাটে সজ্জিত ডাবলটি কীভাবে পড়বেন তা এখানে আপনার হোস্ট কম্পিউটারটি ভিন্ন সিস্টেম ব্যবহার করে।

/*
* read a double from a stream in ieee754 format regardless of host
*  encoding.
*  fp - the stream
*  bigendian - set to if big bytes first, clear for little bytes
*              first
*
*/
double freadieee754(FILE *fp, int bigendian)
{
    unsigned char buff[8];
    int i;
    double fnorm = 0.0;
    unsigned char temp;
    int sign;
    int exponent;
    double bitval;
    int maski, mask;
    int expbits = 11;
    int significandbits = 52;
    int shift;
    double answer;

    /* read the data */
    for (i = 0; i < 8; i++)
        buff[i] = fgetc(fp);
    /* just reverse if not big-endian*/
    if (!bigendian)
    {
        for (i = 0; i < 4; i++)
        {
            temp = buff[i];
            buff[i] = buff[8 - i - 1];
            buff[8 - i - 1] = temp;
        }
    }
    sign = buff[0] & 0x80 ? -1 : 1;
    /* exponet in raw format*/
    exponent = ((buff[0] & 0x7F) << 4) | ((buff[1] & 0xF0) >> 4);

    /* read inthe mantissa. Top bit is 0.5, the successive bits half*/
    bitval = 0.5;
    maski = 1;
    mask = 0x08;
    for (i = 0; i < significandbits; i++)
    {
        if (buff[maski] & mask)
            fnorm += bitval;

        bitval /= 2.0;
        mask >>= 1;
        if (mask == 0)
        {
            mask = 0x80;
            maski++;
        }
    }
    /* handle zero specially */
    if (exponent == 0 && fnorm == 0)
        return 0.0;

    shift = exponent - ((1 << (expbits - 1)) - 1); /* exponent = shift + bias */
    /* nans have exp 1024 and non-zero mantissa */
    if (shift == 1024 && fnorm != 0)
        return sqrt(-1.0);
    /*infinity*/
    if (shift == 1024 && fnorm == 0)
    {

#ifdef INFINITY
        return sign == 1 ? INFINITY : -INFINITY;
#endif
        return  (sign * 1.0) / 0.0;
    }
    if (shift > -1023)
    {
        answer = ldexp(fnorm + 1.0, shift);
        return answer * sign;
    }
    else
    {
        /* denormalised numbers */
        if (fnorm == 0.0)
            return 0.0;
        shift = -1022;
        while (fnorm < 1.0)
        {
            fnorm *= 2;
            shift--;
        }
        answer = ldexp(fnorm, shift);
        return answer * sign;
    }
}

লেখার এবং পূর্ণসংখ্যার রুটিন সহ বাকী স্যুটগুলির জন্য আমার গিথুব প্রকল্পটি দেখুন

https://github.com/MalcolmMcLean/ieee754


0

টেমপ্লেট ফাংশনটিতে পিভটের চারপাশে আপনি পুরানো 3-পদক্ষেপ-জোর ট্রিকের সাথে বাইট অদলবদল একটি নমনীয়, দ্রুত ও (ln2) সমাধান দেয় যা একটি লাইব্রেরির প্রয়োজন হয় না, এখানে শৈলীটি 1 বাইট প্রকারটিকেও প্রত্যাখ্যান করে:

template<typename T>void swap(T &t){
    for(uint8_t pivot = 0; pivot < sizeof(t)/2; pivot ++){
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
        *((uint8_t *)&t+sizeof(t)-1- pivot) ^= *((uint8_t *)&t + pivot);
        *((uint8_t *)&t + pivot) ^= *((uint8_t *)&t+sizeof(t)-1- pivot);
    }
}

0

নিরাপদ উপায়ে মনে হচ্ছে প্রতিটি শব্দে htons ব্যবহার করা। সুতরাং, যদি আপনি ...

std::vector<uint16_t> storage(n);  // where n is the number to be converted

// the following would do the trick
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });

আপনি যদি একটি বড়-এন্ডিয়ান সিস্টেমে থাকেন তবে উপরেরটি কোনও আপত্তি হবে না, তাই আপনার প্ল্যাটফর্মটি সংকলন-সময় শর্ত হিসাবে যেটি ব্যবহার করে তা এইচটিএসটি কোনও নন-ওপেন কিনা তা সন্ধান করতে চাই। এটি সর্বোপরি ও (এন)। ম্যাকের ক্ষেত্রে এটি এমন কিছু হবে ...

#if (__DARWIN_BYTE_ORDER != __DARWIN_BIG_ENDIAN)
std::transform(word_storage.cbegin(), word_storage.cend()
  , word_storage.begin(), [](const uint16_t input)->uint16_t {
  return htons(input); });
#endif

0

আপনার যদি সি ++ 17 থাকে তবে এই শিরোনামটি যুক্ত করুন

#include <algorithm>

বাইটগুলি অদলবদল করতে এই টেম্পলেট ফাংশনটি ব্যবহার করুন:

template <typename T>
void swapEndian(T& buffer)
{
    static_assert(std::is_pod<T>::value, "swapEndian support POD type only");
    char* startIndex = static_cast<char*>((void*)buffer.data());
    char* endIndex = startIndex + sizeof(buffer);
    std::reverse(startIndex, endIndex);
}

এটিকে কল করুন:

swapEndian (stlContainer);

-4

কিছুটা স্থানান্তরিত হওয়া সন্ধান করুন, কারণ সামান্য -> বড় এন্ডিয়ান থেকে অদলবদল করার জন্য এটি মূলত আপনার যা করতে হবে। তারপরে বিট আকারের উপর নির্ভর করে আপনি কীভাবে বিট শিফটিং করবেন তা পরিবর্তন করুন।

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