2

我有一个简短的采访,问题是这样的:设置一个整数值0xaa55在 address 0x*****9

我注意到的唯一一件事是给定的地址没有在字边界上对齐。所以设置int *p地址应该不起作用。那么它只是使用 aunsigned char *p来按字节分配值吗?这是这个面试问题的重点吗?在现实生活中这样做是没有意义的,不是吗?

4

3 回答 3

7

您需要向面试官提出一些附属问题:

  1. 的大小(以字节为单位)是int多少?
  2. 机器是小端还是大端?
  3. 机器是否自动处理非对齐访问?
  4. 自动处理非对齐访问的性能损失是多少?
  5. 这有什么意义?

可能有人正在考虑以快速而肮脏的方式编组数据。

你是对的,一个基本过程是通过 a 写入字节,char *或者unsigned char *初始化为相关地址。我的附属问题 1 和 2 的答案确定了要使用的确切机制,但是对于intlittle-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);
}
于 2012-10-04T06:06:38.057 回答
3
memcpy((void *)0x23456789, &(int){0xaa55}, sizeof(int));
于 2012-10-04T06:21:35.300 回答
0

是的,您可能需要处理现实生活中未对齐的多字节值。想象一下,您的设备与另一台设备交换数据。例如,该数据可能是通过网络发送的消息结构或保存到磁盘的文件结构。该数据的格式可能是预定义的,不受您的控制。并且数据结构的定义可能不考虑设备的对齐(甚至字节序)限制。在这些情况下,您在访问这些未对齐的多字节值时需要小心。

于 2012-10-05T14:33:07.113 回答