Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Set integer value at unaligned address?

Tags:

c

embedded

I had a short interview where a question is like this: set an integer value to be 0xaa55 at address 0x*****9.

The only thing I noticed is that the address given is not aligned on word boundary. So setting an int *p to the address should not work. Then is it just using a unsigned char *p to assign the value byte-wise? Is it the point of this interview question? There is no point of doing this in real life, is there?

like image 444
user1559625 Avatar asked Jul 29 '26 20:07

user1559625


1 Answers

You need to get back to the interviewer with a number of subsidiary questions:

  1. What is the size in bytes of an int?
  2. Is the machine little-endian or big-endian?
  3. Does the machine handle non-aligned access automatically?
  4. What is the performance penalty for handling non-aligned access automatically?
  5. What is the point of this?

The chances are that someone is thinking of marshalling data the quick and dirty way.

You're right that one basic process is to write the bytes via a char * or unsigned char * that is initialized to the relevant address. The answers to my subsidiary questions 1 and 2 determine the exact mechanism to use, but for a 2-byte int in little-endian format, you might use:

unsigned char *p = 0x*****9; // Copied from question!
unsigned int v = 0xAA55;

*p++ = v & 0xFF;
v >>= 8;
*p   = v & 0xFF;

You can generalize to 4-byte or 8-byte integers easily; handling big-endian integers is a bit more fiddly.


I assembled some timing code to see what the relative costs were. Tested on a MacBook Pro (2.3 GHz Intel Core i7, 16 GiB 1333 MHz DDR3 RAM, Mac OS X 10.7.5, home-built GCC 4.7.1), I got the following times for the non-optimized code:

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

When compiled with optimization, I got segmentation faults, even without -DUSE_UNALIGNED — which puzzles me a bit. Debugging was not easy; there seemed to be a lot of aggressive inline optimization which meant that variables could not be printed by the debugger.

The code is below. The Clock type and the time.h header (and timer.c source) are not shown, but can be provided on request (see my profile). They provide high resolution timing across most platforms (Windows is shakiest).

#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);
}
like image 188
Jonathan Leffler Avatar answered Aug 01 '26 09:08

Jonathan Leffler



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!