与えられた16進値の文字列 つまり. 例えば「0011223344」なので、0x00、0x11などになります。
これらの値をchar配列に追加するにはどうすればよいですか?
言うのと同じ:
char array[4] = { 0x00, 0x11 ... };
5バイト相当のデータを4バイトの配列に収めることはできません。これはバッファオーバーフローにつながります。
文字列に16進数がある場合は、sscanf()
とループを使用できます。
#include <stdio.h>
#include <ctype.h>
int main()
{
const char *src = "0011223344";
char buffer[5];
char *dst = buffer;
char *end = buffer + sizeof(buffer);
unsigned int u;
while (dst < end && sscanf(src, "%2x", &u) == 1)
{
*dst++ = u;
src += 2;
}
for (dst = buffer; dst < end; dst++)
printf("%d: %c (%d, 0x%02x)\n", dst - buffer,
(isprint(*dst) ? *dst : '.'), *dst, *dst);
return(0);
}
ゼロバイトで始まる文字列の印刷には注意が必要であることに注意してください。ほとんどの操作は最初のヌルバイトで終了します。このコードはバッファをnullで終了させなかったことに注意してください。ヌル終了が望ましいかどうかは明確ではなく、ターミナルヌルを追加するために宣言したバッファーに十分なスペースがありません(ただし、これは簡単に修正できます)。コードがサブルーチンとしてパッケージ化されている場合、変換された文字列の長さを返す必要がある可能性は十分にあります(ただし、ソース文字列の長さを2で割ったものであると主張することもできます)。
私はこのようなことをします。
// Convert from ascii hex representation to binary
// Examples;
// "00" -> 0
// "2a" -> 42
// "ff" -> 255
// Case insensitive, 2 characters of input required, no error checking
int hex2bin( const char *s )
{
int ret=0;
int i;
for( i=0; i<2; i++ )
{
char c = *s++;
int n=0;
if( '0'<=c && c<='9' )
n = c-'0';
else if( 'a'<=c && c<='f' )
n = 10 + c-'a';
else if( 'A'<=c && c<='F' )
n = 10 + c-'A';
ret = n + ret*16;
}
return ret;
}
int main()
{
const char *in = "0011223344";
char out[5];
int i;
// Hex to binary conversion loop. For example;
// If in="0011223344" set out[] to {0x00,0x11,0x22,0x33,0x44}
for( i=0; i<5; i++ )
{
out[i] = hex2bin( in );
in += 2;
}
return 0;
}
文字列が正しく、その内容を保持する必要がない場合は、次のようにします。
#define hex(c) ((*(c)>='a')?*(c)-'a'+10:(*(c)>='A')?*(c)-'A'+10:*(c)-'0')
void hex2char( char *to ){
for(char *from=to; *from; from+=2) *to++=hex(from)*16+hex(from+1);
*to=0;
}
編集1:申し訳ありませんが、A-F(a-f)の文字で計算するのを忘れています
編集2:私はもっと衒学的なコードを書こうとしました:
#include <string.h>
int xdigit( char digit ){
int val;
if( '0' <= digit && digit <= '9' ) val = digit -'0';
else if( 'a' <= digit && digit <= 'f' ) val = digit -'a'+10;
else if( 'A' <= digit && digit <= 'F' ) val = digit -'A'+10;
else val = -1;
return val;
}
int xstr2str( char *buf, unsigned bufsize, const char *in ){
if( !in ) return -1; // missing input string
unsigned inlen=strlen(in);
if( inlen%2 != 0 ) return -2; // hex string must even sized
for( unsigned i=0; i<inlen; i++ )
if( xdigit(in[i])<0 ) return -3; // bad character in hex string
if( !buf || bufsize<inlen/2+1 ) return -4; // no buffer or too small
for( unsigned i=0,j=0; i<inlen; i+=2,j++ )
buf[j] = xdigit(in[i])*16 + xdigit(in[i+1]);
buf[inlen/2] = '\0';
return inlen/2+1;
}
テスト:
#include <stdio.h>
char buf[100] = "test";
void test( char *buf, const char *s ){
printf("%3i=xstr2str( \"%s\", 100, \"%s\" )\n", xstr2str( buf, 100, s ), buf, s );
}
int main(){
test( buf, (char*)0 );
test( buf, "123" );
test( buf, "3x" );
test( (char*)0, "" );
test( buf, "" );
test( buf, "3C3e" );
test( buf, "3c31323e" );
strcpy( buf, "616263" ); test( buf, buf );
}
結果:
-1=xstr2str( "test", 100, "(null)" )
-2=xstr2str( "test", 100, "123" )
-3=xstr2str( "test", 100, "3x" )
-4=xstr2str( "(null)", 100, "" )
1=xstr2str( "", 100, "" )
3=xstr2str( "", 100, "3C3e" )
5=xstr2str( "", 100, "3c31323e" )
4=xstr2str( "abc", 100, "abc" )
私は同じものを探していて、たくさん読んだ後、ついにこの関数を作成しました。それが役立つかもしれないと思った、誰か
// in = "63 09 58 81"
void hexatoascii(char *in, char* out, int len){
char buf[5000];
int i,j=0;
char * data[5000];
printf("\n size %d", strlen(in));
for (i = 0; i < strlen(in); i+=2)
{
data[j] = (char*)malloc(8);
if (in[i] == ' '){
i++;
}
else if(in[i + 1] == ' '){
i++;
}
printf("\n %c%c", in[i],in[i+1]);
sprintf(data[j], "%c%c", in[i], in[i+1]);
j++;
}
for (i = 0; i < j-1; i++){
int tmp;
printf("\n data %s", data[i] );
sscanf(data[i], "%2x", &tmp);
out[i] = tmp;
}
//printf("\n ascii value of hexa %s", out);
}
これがリトルエンディアンのASCIIプラットフォームであるとしましょう。たぶん、OPは「文字列」ではなく「文字の配列」を意味していました。文字とビットマスキングのペアを使用しています。x16のシフトに注意してください。
/* not my original work, on stacko somewhere ? */
for (i=0;i < 4;i++) {
char a = string[2 * i];
char b = string[2 * i + 1];
array[i] = (((encode(a) * 16) & 0xF0) + (encode(b) & 0x0F));
}
そして関数encode()が定義されています。
unsigned char encode(char x) { /* Function to encode a hex character */
/****************************************************************************
* these offsets should all be decimal ..x validated for hex.. *
****************************************************************************/
if (x >= '0' && x <= '9') /* 0-9 is offset by hex 30 */
return (x - 0x30);
else if (x >= 'a' && x <= 'f') /* a-f offset by hex 57 */
return(x - 0x57);
else if (x >= 'A' && x <= 'F') /* A-F offset by hex 37 */
return(x - 0x37);
}
このアプローチは他の場所に浮かんでいます。それは私のオリジナルの作品ではありませんが、古いものです。ポータブルではないため、純粋主義者には好まれませんが、拡張は簡単です。
私が知っている最良の方法:
int hex2bin_by_zibri(char *source_str, char *dest_buffer)
{
char *line = source_str;
char *data = line;
int offset;
int read_byte;
int data_len = 0;
while (sscanf(data, " %02x%n", &read_byte, &offset) == 1) {
dest_buffer[data_len++] = read_byte;
data += offset;
}
return data_len;
}
この関数は、dest_bufferに保存されている変換されたバイト数を返します。入力文字列には、スペースと大文字と小文字を混在させることができます。
"01 02 03 04 ab CdeFガベージAB"
01 02 03 04 ab cdefを含むdest_bufferに変換されます
また、「01020304abCdeFgarbageAB」
以前と同じように翻訳します。
解析は最初の「エラー」(16進数以外、スペース以外)で停止します。
注:これも有効な文字列です:
"01 2 03 04 ab CdeFガベージAB"
そして生成します:
01 02 03 04 ab cd ef
致命的な床...
これを行うにはいくつかの方法があります...最初に、memcpy()を使用して正確な表現をchar配列にコピーできます。
ビットシフトとビットマスキングの手法も使用できます。宿題の問題のように聞こえるので、これがあなたがしなければならないことだと思います。
最後に、いくつかの凝ったポインタの間接参照を使用して、必要なメモリ位置をコピーできます。
これらの方法はすべてここで詳しく説明されています。
最善の方法を教えてください:
16進文字列から数値、つまりstr [] = "0011223344"から値0x0011223344の場合、
value = strtoul(string, NULL, 16); // or strtoull()
完了しました。 0x00から削除する必要がある場合は、以下を参照してください。
ただし、LITTLE_ENDIANプラットフォームの場合、プラス:16進値からchar配列、値0x11223344からchar arr [N] = {0x00、0x11、...}
unsigned long *hex = (unsigned long*)arr;
*hex = htonl(value);
// you'd like to remove any beginning 0x00
char *zero = arr;
while (0x00 == *zero) { zero++; }
if (zero > arr) memmove(zero, arr, sizeof(arr) - (zero - arr));
完了しました。
注:32ビットシステムで長い文字列を64ビットの16進文字に変換するには、unsignedlongではなくunsignedlong longを使用する必要があります。htonlでは不十分です。htonll、htonqがない可能性があるため、以下のように自分で行ってください。またはhton64など:
#if __KERNEL__
/* Linux Kernel space */
#if defined(__LITTLE_ENDIAN_BITFIELD)
#define hton64(x) __swab64(x)
#else
#define hton64(x) (x)
#endif
#Elif defined(__GNUC__)
/* GNU, user space */
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define hton64(x) __bswap_64(x)
#else
#define hton64(x) (x)
#endif
#Elif
...
#endif
#define ntoh64(x) hton64(x)
http://effocore.googlecode.com/svn/trunk/devel/effo/codebase/builtin/include/impl/sys/bswap.h を参照してください。
{
char szVal[] = "268484927472";
char szOutput[30];
size_t nLen = strlen(szVal);
// Make sure it is even.
if ((nLen % 2) == 1)
{
printf("Error string must be even number of digits %s", szVal);
}
// Process each set of characters as a single character.
nLen >>= 1;
for (size_t idx = 0; idx < nLen; idx++)
{
char acTmp[3];
sscanf(szVal + (idx << 1), "%2s", acTmp);
szOutput[idx] = (char)strtol(acTmp, NULL, 16);
}
}