Commit 53079b9c authored by David Gibson's avatar David Gibson

ptrint: Module for encoding integers into void * pointers

For callbacks which need a void * context pointer in the general case,
there are often simpler cases where an integer would suffice.  These are
often handled by casting the integer into a pointer, rather than having
to allocate that integer somewhere.

This adds a module with some helpers for this.  It has some advantages over
direct casts:
  * It uses pointer arithmetic against NULL instead of casts which should
    make it more portable, even to weird platforms with odd representations
    for NULL.  I don't know the C standard well enough to know if it's
    totally portable though.
  * In particular it means that the truth value of the pointer
    representation matches that of the encoded integer.
  * The conversion functions are inlines providing more type safety than
    raw casts.
  * It uses a ptrint_t * type which can be used to mark such pointer
    encoded integers.  ptrint_t is a deliberately incomplete type so such
    pointers can never be dereferenced.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 9d4ae5f1
../../licenses/CC0
\ No newline at end of file
#include "config.h"
#include <stdio.h>
#include <string.h>
/**
* ptrint - Encoding integers in pointer values
*
* Library (standard or ccan) functions which take user supplied
* callbacks usually have the callback supplied with a void * context
* pointer. For simple cases, it's sometimes sufficient to pass a
* simple integer cast into a void *, rather than having to allocate a
* context structure. This module provides some helper macros to do
* this relatively safely and portably.
*
* The key characteristics of these functions are:
* ptr2int(int2ptr(val)) == val
* and
* !int2ptr(val) == !val
* (i.e. the transformation preserves truth value).
*
* Example:
* #include <ccan/ptrint/ptrint.h>
*
* static void callback(void *opaque)
* {
* int val = ptr2int(opaque);
* printf("Value is %d\n", val);
* }
*
* void (*cb)(void *opaque) = callback;
*
* int main(int argc, char *argv[])
* {
* int val = 17;
*
* (*cb)(int2ptr(val));
* exit(0);
* }
*
* License: CC0 (Public domain)
* Author: David Gibson <david@gibson.dropbear.id.au>
*/
int main(int argc, char *argv[])
{
/* Expect exactly one argument */
if (argc != 2)
return 1;
if (strcmp(argv[1], "depends") == 0) {
printf("ccan/build_assert\n");
return 0;
}
if (strcmp(argv[1], "testdepends") == 0) {
printf("ccan/array_size\n");
return 0;
}
return 1;
}
/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_PTRINT_H
#define CCAN_PTRINT_H
#include "config.h"
#include <stddef.h>
#include <ccan/build_assert/build_assert.h>
/*
* This is a deliberately incomplete type, because it should never be
* dereferenced - instead it marks pointer values which are actually
* encoding integers
*/
typedef struct ptrint ptrint_t;
static inline ptrdiff_t ptr2int(const ptrint_t *p)
{
/*
* ptrdiff_t is the right size by definition, but to avoid
* surprises we want a warning if the user can't fit at least
* a regular int in there
*/
BUILD_ASSERT(sizeof(int) <= sizeof(ptrdiff_t));
return (const char *)p - (const char *)NULL;
}
static inline ptrint_t *int2ptr(ptrdiff_t i)
{
return (ptrint_t *)((char *)NULL + i);
}
#endif /* CCAN_PTRINT_H */
#include <limits.h>
#include <ccan/array_size/array_size.h>
#include <ccan/ptrint/ptrint.h>
#include <ccan/tap/tap.h>
static ptrdiff_t testvals[] = {
-INT_MAX, -1, 0, 1, 2, 17, INT_MAX,
};
int main(void)
{
int i;
/* This is how many tests you plan to run */
plan_tests(2 * ARRAY_SIZE(testvals));
for (i = 0; i < ARRAY_SIZE(testvals); i++) {
ptrdiff_t val = testvals[i];
void *ptr = int2ptr(val);
ok1(ptr2int(ptr) == val);
ok1(!val == !ptr);
}
/* This exits depending on whether all tests passed */
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment