質問が次のような短いインタビューをしました:0xaa55
アドレスに整数値を設定します0x*****9
。
私が気付いた唯一のことは、与えられたアドレスがワード境界に整列されていないということです。したがってint *p
、アドレスにを設定しても機能しないはずです。それではunsigned char *p
、バイト単位で値を割り当てるためにaを使用しているだけですか?このインタビューの質問のポイントですか?実生活でこれを行う意味はありませんね。
いくつかの補助的な質問をしてインタビュアーに戻る必要があります。
int
いくつですか?誰かがデータを迅速かつ汚い方法でマーシャリングすることを考えている可能性があります。
char *
基本的なプロセスの1つは、またはを介してバイトを書き込むことですunsigned char *
。これは、関連するアドレスに初期化されます。私の補助的な質問1と2の回答によって、使用する正確なメカニズムが決まりint
ますが、リトルエンディアン形式の2バイトの場合は、次を使用できます。
unsigned char *p = 0x*****9; // Copied from question!
unsigned int v = 0xAA55;
*p++ = v & 0xFF;
v >>= 8;
*p = v & 0xFF;
4バイトまたは8バイトの整数に簡単に一般化できます。ビッグエンディアン整数の処理は少し面倒です。
いくつかのタイミングコードを組み立てて、相対的なコストを確認しました。MacBook Pro(2.3 GHz Intel Core i7、16 GiB 1333 MHz DDR3 RAM、Mac OS X 10.7.5、自家製GCC 4.7.1)でテストしたところ、最適化されていないコードで次の時間が発生しました。
Aligned: 0.238420
Marshalled: 0.931727
Unaligned: 0.243081
Memcopy: 1.047383
Aligned: 0.239070
Marshalled: 0.931718
Unaligned: 0.242505
Memcopy: 1.060336
Aligned: 0.239915
Marshalled: 0.934913
Unaligned: 0.242374
Memcopy: 1.049218
最適化を使用してコンパイルすると、セグメンテーション違反が発生しましたが、それがなくても-DUSE_UNALIGNED
、少し戸惑いました。デバッグは簡単ではありませんでした。アグレッシブインライン最適化がたくさんあるようで、デバッガーで変数を出力できませんでした。
コードは以下のとおりです。Clock
タイプとtime.h
ヘッダー(およびtimer.c
ソース)は表示されていませんが、要求に応じて提供できます(私のプロファイルを参照)。これらは、ほとんどのプラットフォームで高解像度のタイミングを提供します(Windowsは最も不安定です)。
#include <string.h>
#include <stdio.h>
#include "timer.h"
static int array[100000];
enum { ARRAY_SIZE = sizeof(array) / sizeof(array[0]) };
static int repcount = 1000;
static void uac_aligned(int value)
{
int *base = array;
for (int i = 0; i < repcount; i++)
{
for (int j = 0; j < ARRAY_SIZE - 2; j++)
base[j] = value;
}
}
static void uac_marshalled(int value)
{
for (int i = 0; i < repcount; i++)
{
char *base = (char *)array + 1;
for (int j = 0; j < ARRAY_SIZE - 2; j++)
{
*base++ = value & 0xFF;
value >>= 8;
*base++ = value & 0xFF;
value >>= 8;
*base++ = value & 0xFF;
value >>= 8;
*base = value & 0xFF;
value >>= 8;
}
}
}
#ifdef USE_UNALIGNED
static void uac_unaligned(int value)
{
int *base = (int *)((char *)array + 1);
for (int i = 0; i < repcount; i++)
{
for (int j = 0; j < ARRAY_SIZE - 2; j++)
base[j] = value;
}
}
#endif /* USE_UNALIGNED */
static void uac_memcpy(int value)
{
for (int i = 0; i < repcount; i++)
{
char *base = (char *)array + 1;
for (int j = 0; j < ARRAY_SIZE - 2; j++)
{
memcpy(base, &value, sizeof(int));
base += sizeof(int);
}
}
}
static void time_it(int value, const char *tag, void (*function)(int value))
{
Clock c;
char buffer[32];
clk_init(&c);
clk_start(&c);
(*function)(value);
clk_stop(&c);
printf("%-12s %12s\n", tag, clk_elapsed_us(&c, buffer, sizeof(buffer)));
}
int main(void)
{
int value = 0xAA55;
for (int i = 0; i < 3; i++)
{
time_it(value, "Aligned:", uac_aligned);
time_it(value, "Marshalled:", uac_marshalled);
#ifdef USE_UNALIGNED
time_it(value, "Unaligned:", uac_unaligned);
#endif /* USE_UNALIGNED */
time_it(value, "Memcopy:", uac_memcpy);
}
return(0);
}
memcpy((void *)0x23456789, &(int){0xaa55}, sizeof(int));
はい、実際には、整列されていないマルチバイト値を処理する必要がある場合があります。デバイスが別のデバイスとデータを交換するとします。たとえば、このデータは、ネットワークを介して送信されるメッセージ構造や、ディスクに保存されたファイル構造の場合があります。そのデータの形式は事前定義されている可能性があり、ユーザーが制御することはできません。また、データ構造の定義は、デバイスのアラインメント(またはエンディアン)の制限を考慮していない場合があります。このような状況では、これらの整列されていないマルチバイト値にアクセスするときに注意する必要があります。