在未对齐的地址设置整数值?

时间:2012-10-04 05:55:26

标签: c embedded

我进行了一次简短的采访,问题是这样的:在地址0xaa55设置一个整数值为0x*****9

我唯一注意到的是给定的地址在字边界上没有对齐。因此,将int *p设置为该地址不起作用。那么它只是使用unsigned char *p以字节方式分配值吗?这是面试问题的重点吗?在现实生活中没有必要这样做,是吗?

3 个答案:

答案 0 :(得分:7)

你需要回答面试官的一些辅助问题:

  1. int的字节大小是多少?
  2. 机器是小端还是大端?
  3. 机器是否自动处理非对齐访问?
  4. 自动处理非对齐访问会有什么性能损失?
  5. 这是什么意思?
  6. 有人可能正在考虑以快速而肮脏的方式编组数据。

    您说得对,一个基本过程是通过初始化为相关地址的char *unsigned char *来写入字节。我的子公司问题1和2的答案确定了使用的确切机制,但对于小端格式的2字节int,您可以使用:

    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);
    }
    

答案 1 :(得分:3)

memcpy((void *)0x23456789, &(int){0xaa55}, sizeof(int));

答案 2 :(得分:0)

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