5

I have a function in C which takes a uint8_t * param, which must point to 32-bit aligned memory. Is it possible in C or C++, or with any particular platform's macros, to add some decoration to the parameter, such that the compiler or linker will throw an error at build time if it is not aligned as required?

The idea here is that I want to protect the function against improper use by other users (or me in 6 months). I know how to align the stuff I want to pass to it. I would like to ensure that no one can pass misaligned stuff to it.

Based on this answer, I think the answer to my question is "no", it's not possible to enforce this at build time, but it seems like a useful feature, so I thought I'd check. My work-around is to put assert((((size_t)ptr) % 4) == 0); in the function, so at least I could trap it at runtime when debugging.

In my experience, results are undefined if you cast a misaligned uint8_t* to uint32_t* on many embedded platforms, so I don't want to count on the "correct" result coming out in the end. Plus this is being used on a realtime system, so a slowdown may not be acceptable.

Citations welcome, if there are any.

Community
  • 1
  • 1
cp.engr
  • 2,291
  • 4
  • 28
  • 42
  • Sure not XY problem? Misaligned access on Intel is almost penalty-less, and on strict alignment architecture it would cause SIGBUS anyhow. – SergeyA Jan 27 '17 at 15:52
  • 1
    How would you expect an error at *buld time* for this? That would require quite a lot from the compiler, what if I did `uint8_t* sneaky = (uint8_t*) 1; alignmentRequiringFunction(sneaky);`? Or if `sneaky`'s value came from `fgets()`? One work-around to at least indicate to callers what you expect is to make the argument be `uint32_t *`instead since that implies that natural alignment is expected. – unwind Jan 27 '17 at 15:55
  • @SergeyA, I don't think it's [XY](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). I'm asking about what I think the proper solution would be. Also, I edited the question re - the rest of your comment. – cp.engr Jan 27 '17 at 15:56
  • @unwind, seems to me that the linker (not compiler) could hypothetically do the same alignment check that I'm doing at runtime. – cp.engr Jan 27 '17 at 15:57
  • 1
    @cp.engr *seems to me that the linker (not compiler) could hypothetically do the same alignment check that I'm doing at runtime.* How? The pointer value isn't generally known at link time. – Andrew Henle Jan 27 '17 at 16:00
  • @AndrewHenle, I suppose it could also restrict it to being statically-defined. It would be known at link time then, right? – cp.engr Jan 27 '17 at 16:02
  • 1
    Since the platform apparently is very specific, would it be an option to re-eimplement or wrap `malloc` and `free` to use only aligned memory? – Codor Jan 27 '17 at 16:02
  • 1
    As far as I know, in C++ it is possible to globally overload the `new` and `delete` operators. – Codor Jan 27 '17 at 16:04
  • Just to check alignment? If you want to you can perform pointer arithmetic on it. Probably not universally portable. But convert the pointer to some sort of int with a `reinterpret_cast`, and AND with 0x3; Those are the two least significant bits, and they should be zero for 32bit aligned pointers. – infixed Jan 27 '17 at 16:08

2 Answers2

1

No, there's nothing in the C or C++ standards that I know of that can force a pointer parameter to hold an appropriate value.

To get the memory, use posix_memalign:

#include <stdlib.h>

int posix_memalign(void **memptr, size_t alignment, size_t size);

DESCRIPTION

The posix_memalign() function shall allocate size bytes aligned on a boundary specified by alignment, and shall return a pointer to the allocated memory in memptr. The value of alignment shall be a power of two multiple of sizeof(void *).

Upon successful completion, the value pointed to by memptr shall be a multiple of alignment.

Andrew Henle
  • 32,625
  • 3
  • 24
  • 56
  • Good to know, but I'm on a resource-constrained embedded platform, bare metal firmware development for a realtime system, so we're declaring everything statically. – cp.engr Jan 27 '17 at 16:00
  • @cp.engr If you declare your data as `uin32_t` instead of `uint8_t` (*de facto* `unsigned char`, I suspect), does your platform enforce 32-bit alignment? – Andrew Henle Jan 27 '17 at 16:03
  • True, but I was trying to abstract away the need to cast before passing the parameter. (Indeed, the lower level function casts `uint8_t*` to `uint32_t*`.) I guess I can't have my cake and eat it, too? – cp.engr Jan 27 '17 at 16:11
  • @cp.engr Why not just define your data as `uint32_t`? That would be aligned properly, I'd expect. – Andrew Henle Jan 27 '17 at 16:17
  • Think of future users of the function, not just me right now. I know how to align the struct/array I want to pass to it. – cp.engr Jan 27 '17 at 16:18
  • @cp.engr But if the function has a `uint32_t` alignment requirement, it's not really using `uint8_t` data. – Andrew Henle Jan 27 '17 at 17:21
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/134209/discussion-between-cp-engr-and-andrew-henle). – cp.engr Jan 27 '17 at 17:25
1

For dynamic allocation, have a look at the standard (since C11) aligned_alloc.

For static allocation, I don't know of a standard method, so it'll be compiler dependent. For gcc eg., check the aligned attribute.

Sander De Dycker
  • 16,053
  • 1
  • 35
  • 40
  • Is `aligned_alloc()` part of C++ yet? [This question and its answers](http://stackoverflow.com/questions/29247065/compiler-cant-find-aligned-alloc-function) are a few months old. As far as static alignment, on every platform I've worked on that has alignment requirement for a type, such types are aligned properly by any good compiler, so in this case I'd hope `static uint32_t data[...];` would be aligned naturally on any platform-required alignment. – Andrew Henle Jan 27 '17 at 16:15
  • @AndrewHenle : my answer was intended for C. For C++ you have other options, like [`alignas`](http://en.cppreference.com/w/cpp/language/alignas), [`aligned_storage`](http://en.cppreference.com/w/cpp/types/aligned_storage) or placement new. Re. natural alignment - it sounds reasonable to expect that, but I'm not sure you can rely on such behavior, so consulting your platform documentation is probably a good idea. – Sander De Dycker Jan 27 '17 at 16:21