Next: , Previous: , Up: 2017   [Contents][Index]


C language: cast functions

Posted on Sun Feb 19, 2017

It’s 6AM, milk+coffee makes it one of the best moments of the day.

It happens to define structures as follows, using C11 anonymous fields:

struct alpha_t {
  ...
}

struct beta_t {
  alpha_t;
  ...
}

when using GCC’s -fplan9-extensions facilities: a pointer to beta_t is automatically a pointer to alpha_t.

Sometimes we need to cast a pointer as follows:

alpha_t * A = ...;
beta_t  * B = (beta_t *) A;

the cast operation is obviously dangerous; and it’s also ugly to look at.

So, I will start to experiment with “cast functions”. A cast function from alpha_t to beta_t looks like this, using GCC’s function attributes:

__attribute__((const,always_inline))
static inline beta_t *
cast_to_beta_from_alpha (alpha_t * src)
{
  return (beta_t *)src;
}

this begs for a C11 generic macro:

#define cast_to_beta(SRC)               \
  _Generic((SRC), alpha_t *: cast_to_beta_from_alpha)(SRC)

which will cause a compiler error if applied to a SRC argument which is not an alpha_t pointer. So the cast operation becomes:

alpha_t * A = ...;
beta_t  * B = cast_to_beta(A);

still dangerous. Defining cast functions will not forbid us from using the plain cast operator, but at least it documents which conversions we are, sometimes, expected to do and it provides some type checking.

There’s a lot of keyboard typing in defining a cast function, so we can write a preprocessor macro (which cannot generate the generic macro):

#define DEFINE_CAST_FUNCTION(FROM_NAME,TO_NAME,FROM_TYPE,TO_TYPE) \
  __attribute__((const,always_inline)) static inline TO_TYPE *    \
  cast_to_ ## TO_NAME ## _from_ ## FROM_NAME (FROM_TYPE * src)    \
  { return (TO_TYPE *)src; }

but for now I will try this GNU Emacs template constructor:

(defun my-c-insert-cast-function (PREFIX FROM_NAME TO_NAME)
  "Insert a C language cast function.

The call:

  (my-c-insert-cast-function \"ccevents\" \"source\" \"fd_source\")

will insert:

  /* Output of: (my-c-insert-cast-function \"ccevents\" \"source\" \"fd_source\") */
  __attribute__((const,always_inline))
  static inline ccevents_fd_source_t *
  ccevents_cast_to_fd_source_from_source (ccevents_source_t * src)
  {
    return (ccevents_fd_source_t *)src;
  }
  #define ccevents_cast_to_fd_source(SRC)         \\
    _Generic((SRC), ccevents_source_t *: ccevents_cast_to_fd_source_from_source)(SRC)
  /* End of output. */"
  (interactive "*sPrefix: \n\
sFrom name: \n\
sTo name: ")
  (insert (concat "/* Output of: (my-c-insert-cast-function \"" PREFIX "\" \"" FROM_NAME "\" \"" TO_NAME "\") */
__attribute__((const,always_inline))
static inline " PREFIX "_" TO_NAME "_t *
" PREFIX "_cast_to_" TO_NAME "_from_" FROM_NAME " (" PREFIX "_" FROM_NAME "_t * src)
{
  return (" PREFIX "_" TO_NAME "_t *)src;
}
#define " PREFIX "_cast_to_" TO_NAME "(SRC)             \\
  _Generic((SRC), " PREFIX "_" FROM_NAME "_t *: " PREFIX "_cast_to_" TO_NAME "_from_" FROM_NAME ")(SRC)
/* End of output. */
")))

which, explicitly called from Emacs’ minibuffer , produces the following text:

/* Output of: (my-c-insert-cast-function "ccevents" "source" "fd_source") */
__attribute__((const,always_inline))
static inline ccevents_fd_source_t *
ccevents_cast_to_fd_source_from_source (ccevents_source_t * src)
{
  return (ccevents_fd_source_t *)src;
}
#define ccevents_cast_to_fd_source(SRC)         \
  _Generic((SRC), ccevents_source_t *: ccevents_cast_to_fd_source_from_source)(SRC)
/* End of output. */

Neat.


Next: , Previous: , Up: 2017   [Contents][Index]