我有一个简短的采访,问题是这样的:设置一个整数值0xaa55
在 address 0x*****9
。
我注意到的唯一一件事是给定的地址没有在字边界上对齐。所以设置int *p
地址应该不起作用。那么它只是使用 aunsigned char *p
来按字节分配值吗?这是这个面试问题的重点吗?在现实生活中这样做是没有意义的,不是吗?
您需要向面试官提出一些附属问题:
int
多少?可能有人正在考虑以快速而肮脏的方式编组数据。
你是对的,一个基本过程是通过 a 写入字节,char *
或者unsigned char *
初始化为相关地址。我的附属问题 1 和 2 的答案确定了要使用的确切机制,但是对于int
little-endian 格式的 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));
是的,您可能需要处理现实生活中未对齐的多字节值。想象一下,您的设备与另一台设备交换数据。例如,该数据可能是通过网络发送的消息结构或保存到磁盘的文件结构。该数据的格式可能是预定义的,不受您的控制。并且数据结构的定义可能不考虑设备的对齐(甚至字节序)限制。在这些情况下,您在访问这些未对齐的多字节值时需要小心。