Cのインタビューで、数字の最初の4ビットを最後の4ビットと交換するように求められました。 (例:10111110は11101011である必要があります。)
誰かがこれに対する解決策を持っていますか?
少しいじくり回しているのを見たことがない、または行ったことがない場合は、次のことを学習してください。
unsigned char c;
c = ((c & 0xf0) >> 4) | ((c & 0x0f) << 4);
この種の面接の質問に対する「正解」はありません。これを行うにはいくつかの方法があり(ルックアップテーブル、誰か?)、それぞれの方法の間のトレードオフ(読みやすさ、パフォーマンス、移植性、保守性)について説明する必要があります。
問題は、上記の問題のいくつかについて議論し、そのような問題について「深く」議論できるかどうかを判断するための最初のギャンビットにすぎません。
一時変数を使用して最後のビットをその変数に移動し、ビットをその方向にシフトして、tmp変数のビットのマスキングを終了するだけで完了です。
更新:コードを追加して、読みやすいものを選択してみましょう。
働くワンライナー
unsigned int data = 0x7654;
data = (data ^ data & 0xff) | ((data & 0xf) << 4) | ((data & 0xf0) >> 4);
printf("data %x \n", data);
同じコードですが、いくつかのtmp変数があります
unsigned int data = 0x7654;
unsigned int tmp1 = 0;
unsigned int tmp2 = 0;
tmp1 = (0x0f&data)<<4;
tmp2 = (0xf0&data)>>4;
tmp1 = tmp1 | tmp2;
data = data ^ (data & 0xff);
data = data | tmp1;
printf("data %x \n", data);
まあ、とにかくワンライナーは短いです:)
更新:
そして、gccが-Os -Sで生成したasmコードを見ると、「コンパイラの最適化」の部分でオーバーヘッドが削除されるため、ほぼ同じであると思います。
一時変数は必要ありません。次のような方法で実行できます。
x = ((x & 0xf) << 4) | ((x & 0xf0) >> 4);
x
の正確なタイプによっては、これには潜在的な落とし穴があります。この問題の特定は、読者の演習として残されています。
C++のような擬似コード(一時変数を使用しないように簡単に書き直すことができます):
int firstPart = source & 0xF;
int offsetToHigherPart = sizeof( source ) * CHAR_BIT - 4;
int secondPart = ( source >> offsetToHigherPart ) & 0xF;
int maskToSeparateMiddle = -1 & ( ~0xF ) & ( ~( 0xF << offsetToHigherPart );
int result = ( firstPart << offsetToHigherPart ) | secondPart | (source & maskToSeparateMiddle);
これには、CHAR_BITを定義する必要があります。これは通常limits.hにあり、8ビットとして定義されていますが、厳密に言えばプラットフォームに依存しており、ヘッダーでまったく定義できません。
unsigned char b;
b = (b << 4) | (b >> 4);
標準のビットシフトよりも賢いものをお探しですか?
(aが8ビット型であると仮定)
a = ((a >> 4) & 0xF) + ((a << 4) &0xF0)
x86アセンブリ:
asm{
mov AL, 10111110b
rol AL
rol AL
rol AL
rol AL
}
http://www.geocities.com/SiliconValley/Park/3230/x86asm/asml1005.html
最後と最初の間で一般的なnビットを交換するためのソリューション。合計ビットが2n未満の場合は検証されません。ここで、7は文字、31は整数です。
unsigned char swapNbitsFtoL(unsigned char num, char nbits)
{
unsigned char u1 = 0;
unsigned char u2 = 0;
u1 = ~u1;
u1 &= num;
u1 = (u1 >> (7 - (nbits - 1))); /* Here nbits is number of n=bits so I have taken (nbits - 1). */
u2 = ~u2;
u2 &= num;
u2 = (u2 << (7 - (nbits - 1))); /* Here nbits is number of n=bits so I have taken (nbits - 1). */
u1 |= u2; /* u1 have first and last swapped n bits with */
u2 = 0;
u2 = ~u2;
u2 = ((u2 >> (7 - (nbits - 1))) | (u2 << (7 - (nbits - 1))));
bit_print(u2);
u2 = ~u2;
u2 &= num;
return (u1 | u2);
}
これは、ビットを完全に交換して、バイトのビットエンディアンを変更する方法です。
「iIn」は、ファイルからの読み取りに使用しているため、実際には整数です。簡単に順番に読み取れる順序でビットが必要です。
// swap bits
iIn = ((iIn>>4) & 0x0F) | ((iIn<<4) & 0xF0); // THIS is your solution here.
iIn = ((iIn>>2) & 0x33) | ((iIn<<2) & 0xCC);
iIn = ((iIn>>1) & 0x55) | ((iIn<<1) & 0xAA);
1バイトで2つのニブルだけを交換する場合、これはこれを行うための最も効率的な方法であり、ほとんどの状況でルックアップテーブルよりもおそらく高速です。
多くの人がシフトをしていて、ここでマスキングをするのを忘れているのを目にします。これは、符号拡張がある場合の問題です。 unsigned charのタイプがある場合、それはunsigned 8ビット量であるため問題ありませんが、他のタイプでは失敗します。
マスクはオーバーヘッドを追加せず、unsigned charを使用します。マスクはとにかく暗示され、適切なコンパイラーは不要なコードを削除し、20年間使用します。
/*swaping four bits*/
#include<stdio.h>
void printb(char a) {
int i;
for( i = 7; i >= 0; i--)
printf("%d", (1 & (a >> i)));
printf("\n");
}
int swap4b(char a) {
return ( ((a & 0xf0) >> 4) | ((a & 0x0f) << 4) );
}
int main()
{
char a = 10;
printb(a);
a = swap4b(a);
printb(a);
return 0;
}
最も簡単なのは(tは符号なしです):
t = (t>>4)|(t<<4);
ただし、コードを難読化したい場合、または他のビットの組み合わせを交換したい場合は、次のベースを使用できます。
mask = 0x0F & (t ^ (t >> 4));
t ^= (mask | (mask << 4));