演習の目的は、メモリレイアウトに基づいて整数を文字列に変換してから、元に戻すことであるように見えます。
そうでなければ、バイト境界にいるかどうかを判断してから、ビットシフトの「体操」を行うことをいじくり回すことはありません。むしろ、値を4だけ左にシフトして、次のように次の桁を追加します。
#include <stdio.h>
#include <string.h>
short dehex (char hexLetter) {
if ((hexLetter >= '0') && (hexLetter <= '9'))
return hexLetter - '0';
return hexLetter - 'A' + 10;
}
int main (void) {
unsigned int o = 0;
char *in = "D2029649";
int len = strlen (in);
for (int i = 0; i < len; i++)
o = (o << 4) + dehex (in[i]);
printf ("%X\n", o);
return 0;
}
dehex
文字定数がはるかに読みやすいマジックナンバーの大ファンではないため、関数を少し変更したことに気付くでしょう(EBCDICなどのすべての実装に移植できるわけではありませんが、最近では貴重なものはほとんどありません。 )。
このプログラムは、チェックのために、その文字列から符号なし整数値を大文字の16進数で出力しますD2029649
。
ただし、1234567890
10進数の値は、16進数で499602D2
、文字列にあるバイトの順序とは逆のバイトの順序になっています。これは、リトルエンディアンアーキテクチャとして知られているものを使用しているためです。
したがって、2つの問題があります。
1つ目は、元の番号を取得するために間違った順序でバイトを処理していることです。
文字列の最後から始めて、次のように逆方向に作業する必要があります。
for (int i = len - 2; i >= 0; i -= 2) ...
2つ目は、追加/シフト操作を間違った順序で実行していることです。
元のコードは追加後D2029649
にシフトしたため、左に8ビットシフトし02964900
てD2
から、左から忘却にシフトし、右に0バイトがシフトインしました。シフトしてから追加する必要があります:
o <<= 8;
o |= ((unsigned char)dehex(in[i]) << 4) + dehex(in[i+1]);
最後に、必須ではありませんが、変換されたニブルを返すためにunsigned charを使用するだけで、コードをかなり単純化できます。私が書くコードは次の行に沿っています:
#include <stdio.h>
#include <string.h>
unsigned char dehex (char hexLetter) {
if ((hexLetter >= '0') && (hexLetter <= '9'))
return hexLetter - '0';
return hexLetter - 'A' + 10;
}
int main (void) {
unsigned int num = 1234567890;
char *p = (char*) #
for (int i = 0; i < 4; i++)
printf("%X%X", (*(p+i) & 0xF0) >> 4, *(p+i) & 0x0F);
putchar ('\n');
unsigned int o = 0;
char *in = "D2029649";
int len = strlen (in);
for (int i = len - 2; i >= 0; i -= 2) {
o <<= 8;
o |= (dehex (in[i]) << 4) + dehex (in[i+1]);
}
printf ("%X, or %u\n", o, o);
return 0;
}
これは、一度にニブルではなく、一度に1バイトずつ実行するという点ではるかに理にかなっていることに注意してください。ニブルベースのコードでは、小さなループ6, 7, 4, 5, 2, 3, 0, 1
ではなく、配列インデックスを順番に実行する必要があります。0..7
このプログラムの出力は次のとおりです。
D2029649
499602D2, or 1234567890
元の番号に戻っていることを示しています。