বড় এন্ডিয়ানকে সি-তে ছোট এন্ডিয়ান রূপান্তর করতে আমার একটি ফাংশন লিখতে হবে আমি কোনও লাইব্রেরি ফাংশন ব্যবহার করতে পারি না।
বড় এন্ডিয়ানকে সি-তে ছোট এন্ডিয়ান রূপান্তর করতে আমার একটি ফাংশন লিখতে হবে আমি কোনও লাইব্রেরি ফাংশন ব্যবহার করতে পারি না।
উত্তর:
আপনার যা প্রয়োজন তা ধরে নেওয়া একটি সাধারণ বাইট অদলবদল, এরকম কিছু চেষ্টা করুন
স্বাক্ষরযুক্ত 16 বিট রূপান্তর:
swapped = (num>>8) | (num<<8);
স্বাক্ষরযুক্ত 32-বিট রূপান্তর:
swapped = ((num>>24)&0xff) | // move byte 3 to byte 0
((num<<8)&0xff0000) | // move byte 1 to byte 2
((num>>8)&0xff00) | // move byte 2 to byte 1
((num<<24)&0xff000000); // byte 0 to byte 3
এটি 1234 থেকে 4321 পজিশন থেকে বাইট অর্ডারগুলি অদলবদল করে। যদি আপনার ইনপুটটি থাকে তবে 0xdeadbeef
একটি 32-বিট এন্ডিয়ান স্বাপের আউটপুট থাকতে পারে 0xefbeadde
।
উপরের কোডটি যাদু সংখ্যার পরিবর্তে ম্যাক্রো বা কমপক্ষে ধ্রুবক দিয়ে পরিষ্কার করা উচিত, তবে আশা করি এটি যেমনটি সহায়তা করে
সম্পাদনা: অন্য উত্তর হিসাবে উল্লেখ করা হয়েছে, প্ল্যাটফর্ম, ওএস এবং নির্দেশাবলী নির্দিষ্ট বিকল্প রয়েছে যা উপরের চেয়ে অনেক বেশি দ্রুত হতে পারে। লিনাক্স কার্নেলে ম্যাক্রোগুলি রয়েছে (উদাহরণস্বরূপ cpu_to_be32) যা সুন্দরভাবে সুন্দরভাবে পরিচালনা করে। তবে এই বিকল্পগুলি তাদের পরিবেশের সাথে নির্দিষ্ট। অনুশীলনে অন্তর্নিহিততা উপলব্ধ পদ্ধতির মিশ্রণটি ব্যবহার করে সবচেয়ে ভাল আচরণ করা হয়
((num & 0xff) >> 8) | (num << 8)
, জিসিসি 4.8.3 একটি একক rol
নির্দেশ উত্পন্ন করে । এবং যদি 32 বিট রূপান্তর হিসাবে লেখা হয় তবে ((num & 0xff000000) >> 24) | ((num & 0x00ff0000) >> 8) | ((num & 0x0000ff00) << 8) | (num << 24)
একই সংকলক একটি একক bswap
নির্দেশ উত্পন্ন করে ।
struct byte_t reverse(struct byte_t b) { struct byte_t rev; rev.ba = b.bh; rev.bb = b.bg; rev.bc = b.bf; rev.bd = b.be; rev.be = b.bd; rev.bf = b.bc; rev.bg = b.bb; rev.bh = b.ba; return rev;}
যেখানে এটি 8 টি ক্ষেত্র 1 বিট প্রতি বিটফিল্ড। তবে আমি নিশ্চিত নই যে অন্যান্য পরামর্শগুলির মতো দ্রুত if ইনটসের জন্য union { int i; byte_t[sizeof(int)]; }
পূর্ণসংখ্যায় বাইট বাই বিপরীত করতে ব্যবহার করুন ।
অন্তর্ভুক্ত দ্বারা:
#include <byteswap.h>
আপনি মেশিন-নির্ভর বাইট-সোয়াপিং ফাংশনগুলির একটি অনুকূলিত সংস্করণ পেতে পারেন। তারপরে, আপনি সহজেই নিম্নলিখিত ফাংশনগুলি ব্যবহার করতে পারেন:
__bswap_32 (uint32_t input)
বা
__bswap_16 (uint16_t input)
#include <byteswap.h>
, .h ফাইল নিজেই মন্তব্য দেখুন। এই পোস্টে সহায়ক তথ্য রয়েছে তাই আমি লিপ ফাংশনটি ব্যবহার না করার জন্য ওপি প্রয়োজনীয়তা উপেক্ষা করে লেখক সত্ত্বেও আমি ভোট দিয়েছি।
#include <stdint.h>
//! Byte swap unsigned short
uint16_t swap_uint16( uint16_t val )
{
return (val << 8) | (val >> 8 );
}
//! Byte swap short
int16_t swap_int16( int16_t val )
{
return (val << 8) | ((val >> 8) & 0xFF);
}
//! Byte swap unsigned int
uint32_t swap_uint32( uint32_t val )
{
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0xFF00FF );
return (val << 16) | (val >> 16);
}
//! Byte swap int
int32_t swap_int32( int32_t val )
{
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF );
return (val << 16) | ((val >> 16) & 0xFFFF);
}
আপডেট : 64 বিট বাইট অদলবদল করা হয়েছে
int64_t swap_int64( int64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | ((val >> 32) & 0xFFFFFFFFULL);
}
uint64_t swap_uint64( uint64_t val )
{
val = ((val << 8) & 0xFF00FF00FF00FF00ULL ) | ((val >> 8) & 0x00FF00FF00FF00FFULL );
val = ((val << 16) & 0xFFFF0000FFFF0000ULL ) | ((val >> 16) & 0x0000FFFF0000FFFFULL );
return (val << 32) | (val >> 32);
}
int32_t
এবং int64_t
রূপগুলো, এর মাস্কিং পিছনে যুক্তি কি ... & 0xFFFF
এবং ... & 0xFFFFFFFFULL
? এখানে সাইন-এক্সটেনশন নিয়ে কিছু চলছে যা আমি দেখছি না? এছাড়াও, কেন swap_int64
ফিরছে uint64_t
? তা কি হওয়া উচিত নয় int64_t
?
swap_int64
নিজের উত্তরের জন্য রিটার্ন মানটির ধরণটি পরিবর্তন করতে চাইতে পারেন । সহায়ক উত্তরের জন্য +1, বিটিডাব্লু!
LL
অপ্রয়োজনীয় হয় (u)swap_uint64()
অনেক একটি মত L
এ প্রয়োজন হয় না (u)swap_uint32()
। U
প্রয়োজন হয় না uswap_uint64()
অনেক মত U
মধ্যে প্রয়োজন হয় নাuswap_uint32()
এখানে একটি মোটামুটি জেনেরিক সংস্করণ; আমি এটি সংকলন করি নি, সুতরাং সম্ভবত টাইপস রয়েছে, তবে আপনার ধারণাটি পাওয়া উচিত,
void SwapBytes(void *pv, size_t n)
{
assert(n > 0);
char *p = pv;
size_t lo, hi;
for(lo=0, hi=n-1; hi>lo; lo++, hi--)
{
char tmp=p[lo];
p[lo] = p[hi];
p[hi] = tmp;
}
}
#define SWAP(x) SwapBytes(&x, sizeof(x));
নোট: এটিগতি বা স্থানের জন্য অনুকূলিত নয় । এটি পরিষ্কার (ডিবাগ করা সহজ) এবং বহনযোগ্য to
আপডেট 2018-04-04 কমেন্টার @chux দ্বারা চিহ্নিত হিসাবে n == 0 এর অবৈধ কেস ফাঁদে ফেলার জন্য দৃ as়তা () যোগ করেছে।
bswap
অপ্টিমাইজেশান সক্ষম সহ একটি শালীন X86 সংকলক দ্বারা একটি নির্দেশে সংকলিত হয়েছে । আকারের পরামিতি সহ এই সংস্করণটি এটি করতে পারে নি।
আপনার যদি ম্যাক্রোগুলির প্রয়োজন হয় (যেমন এম্বেডেড সিস্টেম):
#define SWAP_UINT16(x) (((x) >> 8) | ((x) << 8))
#define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24))
UINT
তাদের নামে রয়েছে।
সম্পাদনা করুন: এগুলি গ্রন্থাগার ফাংশন। তাদের অনুসরণ করা এটি করার ম্যানুয়াল উপায়।
__Byteswap_ushort, __bywap_ulong, এবং __byteswap_uint64 সম্পর্কে অজানা লোকের সংখ্যা শুনে আমি একেবারে হতবাক । নিশ্চিত যে এগুলি ভিজ্যুয়াল সি ++ নির্দিষ্ট, তবে তারা x86 / IA-64 আর্কিটেকচারের কিছু সুস্বাদু কোডটি সংকলন করে। :)
এই পৃষ্ঠাটি থেকে টানাbswap
নির্দেশের একটি স্পষ্ট ব্যবহার এখানে । নোট করুন যে উপরের অভ্যন্তরীণ ফর্মটি সর্বদা এর চেয়ে দ্রুততর হবে , আমি কেবল এটি লাইব্রেরির রুটিন ছাড়া উত্তর দেওয়ার জন্য যুক্ত করেছি।
uint32 cq_ntohl(uint32 a) {
__asm{
mov eax, a;
bswap eax;
}
}
রসিকতা হিসাবে:
#include <stdio.h>
int main (int argc, char *argv[])
{
size_t sizeofInt = sizeof (int);
int i;
union
{
int x;
char c[sizeof (int)];
} original, swapped;
original.x = 0x12345678;
for (i = 0; i < sizeofInt; i++)
swapped.c[sizeofInt - i - 1] = original.c[i];
fprintf (stderr, "%x\n", swapped.x);
return 0;
}
int i, size_t sizeofInt
এবং উভয়ের জন্য একই ধরনের।
এখানে এসএসএসই 3 নির্দেশনাটি শুশবকে এর ইনটেল অভ্যন্তরীণ ব্যবহার করে এমন এক উপায় রয়েছে যা ধরে নিই যে আপনার 4 টির একাধিক রয়েছে int
:
unsigned int *bswap(unsigned int *destination, unsigned int *source, int length) {
int i;
__m128i mask = _mm_set_epi8(12, 13, 14, 15, 8, 9, 10, 11, 4, 5, 6, 7, 0, 1, 2, 3);
for (i = 0; i < length; i += 4) {
_mm_storeu_si128((__m128i *)&destination[i],
_mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&source[i]), mask));
}
return destination;
}
এই কাজটি কি দ্রুত হবে?
uint32_t swapped, result;
((byte*)&swapped)[0] = ((byte*)&result)[3];
((byte*)&swapped)[1] = ((byte*)&result)[2];
((byte*)&swapped)[2] = ((byte*)&result)[1];
((byte*)&swapped)[3] = ((byte*)&result)[0];
char
, না byte
।
এখানে আমি ব্যবহার করছি এমন কোনও ফাংশন - পরীক্ষিত এবং কোনও বুনিয়াদি ডেটা ধরণের উপর কাজ করে:
// SwapBytes.h
//
// Function to perform in-place endian conversion of basic types
//
// Usage:
//
// double d;
// SwapBytes(&d, sizeof(d));
//
inline void SwapBytes(void *source, int size)
{
typedef unsigned char TwoBytes[2];
typedef unsigned char FourBytes[4];
typedef unsigned char EightBytes[8];
unsigned char temp;
if(size == 2)
{
TwoBytes *src = (TwoBytes *)source;
temp = (*src)[0];
(*src)[0] = (*src)[1];
(*src)[1] = temp;
return;
}
if(size == 4)
{
FourBytes *src = (FourBytes *)source;
temp = (*src)[0];
(*src)[0] = (*src)[3];
(*src)[3] = temp;
temp = (*src)[1];
(*src)[1] = (*src)[2];
(*src)[2] = temp;
return;
}
if(size == 8)
{
EightBytes *src = (EightBytes *)source;
temp = (*src)[0];
(*src)[0] = (*src)[7];
(*src)[7] = temp;
temp = (*src)[1];
(*src)[1] = (*src)[6];
(*src)[6] = temp;
temp = (*src)[2];
(*src)[2] = (*src)[5];
(*src)[5] = temp;
temp = (*src)[3];
(*src)[3] = (*src)[4];
(*src)[4] = temp;
return;
}
}
source
প্রয়োজনীয় হিসাবে প্রান্তিক করা হয় - তবুও যদি এই অনুমানটি ধরে না রাখে, কোডটি ইউবি।
সম্পাদনা: এই ফাংশনটি কেবলমাত্র 16 বিট শব্দের প্রান্তিককরণের পরিবর্তন করে। ইউটিএফ -16 / ইউসিএস -2 এনকোডিংয়ের জন্য প্রায়শই প্রয়োজনীয় একটি ক্রিয়াকলাপ। সম্পাদনা সমাপ্তি।
আপনি যদি কোনও মেমরির ব্লকের অন্তর্নিহিততা পরিবর্তন করতে চান তবে আপনি আমার নির্লজ্জভাবে দ্রুত পদ্ধতির ব্যবহার করতে পারেন। আপনার মেমরি অ্যারের একটি আকার হওয়া উচিত যা 8 এর একাধিক।
#include <stddef.h>
#include <limits.h>
#include <stdint.h>
void ChangeMemEndianness(uint64_t *mem, size_t size)
{
uint64_t m1 = 0xFF00FF00FF00FF00ULL, m2 = m1 >> CHAR_BIT;
size = (size + (sizeof (uint64_t) - 1)) / sizeof (uint64_t);
for(; size; size--, mem++)
*mem = ((*mem & m1) >> CHAR_BIT) | ((*mem & m2) << CHAR_BIT);
}
এই জাতীয় ফাংশন ইউনিকোড ইউসিএস -২ / ইউটিএফ -16 ফাইলের অন্তর্নিহিতা পরিবর্তনের জন্য দরকারী।
t know if it
পরামর্শগুলির মতো তত তাড়াতাড়ি এগিয়ে যাচ্ছি তবে তা অবাক হয়ে যায়: github.com/heatblazer/helpers/blob/master/utils.h
CHAR_BIT
পরিবর্তে নির্ভরশীল 8
হিসাবে 0xFF00FF00FF00FF00ULL
কৌতূহলযুক্ত CHAR_BIT == 8
। নোট করুন যে LL
ধ্রুবক প্রয়োজন হয় না।
CHAR_BIT
সেই ম্যাক্রোর এক্সপোজার বাড়ানোর জন্যই লিখেছিলেন । এলএল হিসাবে, এটি অন্য যে কোনও কিছুর চেয়ে বেশি টিকা। এটি একটি অভ্যাস যা আমি বহুদিন আগে বাগি সংকলক (প্রাক মান) দিয়েছিলাম যা সঠিক কাজটি করে না।
এই কোড স্নিপেট 32 বিট লিট এন্ডিয়ান সংখ্যাটিকে বিগ এন্ডিয়ান সংখ্যায় রূপান্তর করতে পারে।
#include <stdio.h>
main(){
unsigned int i = 0xfafbfcfd;
unsigned int j;
j= ((i&0xff000000)>>24)| ((i&0xff0000)>>8) | ((i&0xff00)<<8) | ((i&0xff)<<24);
printf("unsigned int j = %x\n ", j);
}
আপনি যদি একটি x86 বা x86_64 প্রসেসরের উপর চালনা করেন তবে বড় এন্ডিয়ান স্থানীয় হয়। তাই
16 বিট মান জন্য
unsigned short wBigE = value;
unsigned short wLittleE = ((wBigE & 0xFF) << 8) | (wBigE >> 8);
32 বিট মানগুলির জন্য
unsigned int iBigE = value;
unsigned int iLittleE = ((iBigE & 0xFF) << 24)
| ((iBigE & 0xFF00) << 8)
| ((iBigE >> 8) & 0xFF00)
| (iBigE >> 24);
এটি সর্বাধিক দক্ষ সমাধান নয় যতক্ষণ না সংকলকটি স্বীকৃতি দেয় যে এটি বাইট লেভেল ম্যানিপুলেশন এবং বাইট অদলবদ কোড উত্পন্ন করে না। তবে এটি কোনও মেমরি বিন্যাসের কৌশলগুলির উপর নির্ভর করে না এবং খুব সহজেই ম্যাক্রোতে রূপান্তরিত হতে পারে।