मुझे सी में छोटे एंडियन में बड़े एंडियन को बदलने के लिए एक फ़ंक्शन लिखने की आवश्यकता है। मैं किसी भी लाइब्रेरी फ़ंक्शन का उपयोग नहीं कर सकता हूं।
मुझे सी में छोटे एंडियन में बड़े एंडियन को बदलने के लिए एक फ़ंक्शन लिखने की आवश्यकता है। मैं किसी भी लाइब्रेरी फ़ंक्शन का उपयोग नहीं कर सकता हूं।
जवाबों:
यह मानते हुए कि आपको एक साधारण बाइट स्वैप की आवश्यकता है, कुछ ऐसा प्रयास करें
निरस्त 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
।
ऊपर दिए गए कोड को मैक्रो या मैजिक नंबर के बजाय कम से कम स्थिरांक से साफ किया जाना चाहिए, लेकिन उम्मीद है कि यह मदद करता है
EDIT: जैसा कि एक अन्य उत्तर में बताया गया है, प्लेटफ़ॉर्म, OS और निर्देश सेट विशिष्ट विकल्प हैं जो उपरोक्त से अधिक तेज़ हो सकते हैं। लिनक्स कर्नेल में मैक्रोज़ (उदाहरण के लिए cpu_to_be32) हैं, जो एंडियननेस को बहुत अच्छी तरह से संभालते हैं। लेकिन ये विकल्प उनके वातावरण के लिए विशिष्ट हैं। व्यवहार में अंतःकरण उपलब्ध दृष्टिकोणों के मिश्रण का उपयोग करने के लिए सबसे अच्छा है
((num & 0xff) >> 8) | (num << 8)
, तो gcc 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 बिट प्रत्येक के साथ बिटफ़ील्ड है। लेकिन मुझे यकीन नहीं है कि अन्य सुझावों के रूप में उपवास करता है। Ints के 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, BTW!
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));
NB: यहगति या स्थान के लिए अनुकूलित नहीं है। यह स्पष्ट (डीबग करने में आसान) और पोर्टेबल होने का इरादा है।
अपडेट 2018-04-04 ने n == 0 के अमान्य मामले को फंसाने के लिए ( @) जोड़ा, जैसा कि टिप्पणीकर्ता @chux द्वारा देखा गया है।
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, __byteswap_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
और दोनों के लिए एक ही प्रकार नहीं।
यहाँ एक तरीका है SSSE3 इंस्ट्रक्शन pshufb का उपयोग करके अपने इंटेल आंतरिक का उपयोग करते हुए, यह मानते हुए कि आपके पास 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
आवश्यकतानुसार गठबंधन किया जाता है - फिर भी यदि वह धारणा धारण नहीं करता है, तो कोड यूबी है।
EDIT: यह फ़ंक्शन केवल 16 बिट शब्दों के संरेखित किए गए अंतरण को स्वैप करता है। एक फ़ंक्शन अक्सर UTF-16 / UCS-2 एन्कोडिंग के लिए आवश्यक होता है। संपादित करें END।
यदि आप एक मेमोरी ब्लॉक की समाप्ति को बदलना चाहते हैं तो आप मेरे धधकते हुए तेज़ दृष्टिकोण का उपयोग कर सकते हैं। आपकी मेमोरी सरणी का आकार 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);
}
इस तरह का फ़ंक्शन यूनिकोड यूसीएस -2 / यूटीएफ -16 फाइलों की समाप्ति को बदलने के लिए उपयोगी है।
t know if it
सुझाव के रूप में तेजी से डॉन है, लेकिन यह wokrs: 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);
जब तक कंपाइलर यह बाइट स्तर में हेरफेर नहीं करता है और बाइट स्वैपिंग कोड उत्पन्न करता है, तब तक यह सबसे कुशल समाधान नहीं है। लेकिन यह किसी भी मेमोरी लेआउट ट्रिक पर निर्भर नहीं करता है और इसे आसानी से मैक्रो में बदल दिया जा सकता है।