qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH 2/2] Introduce macro for defining qdev propertie


From: Jamie Lokier
Subject: Re: [Qemu-devel] [PATCH 2/2] Introduce macro for defining qdev properties
Date: Mon, 20 Jul 2009 03:29:05 +0100
User-agent: Mutt/1.5.13 (2006-08-11)

Anthony Liguori wrote:
> Jamie Lokier wrote:
> >In (hopefully) ANSI-portable C code which performs a very similar
> >function, I got it down to OPTION_SIGNED("name", var),
> >OPTION_UNSIGNED("name", var), OPTION_BOOL("name", var),
> >OPTION_STRING("name", var), for the major non-compound types.
> >  
> How do you detect the size of the integer?

Using sizeof(var) :-)

The macros expand to something like

    { name, (void *)&var, sizeof(var),
      SIGNED_MIN_FROM_SIZE(sizeof(var)),
      SIGNED_MAX_FROM_SIZE(sizeof(var)),      
      option_parse_signed },

option_parse_signed is a generic integer parsing function, parsing any
size integer up to intmax_t.  The result is checked against the min
and max fields, which are calculated at compile time.  The _RANGE
version of the macros lets you set them explicitly instead.

Then all parsing functions use the code attached below to store the
value in the correct variable size.

In my app I also include OPTION_SET_{FALSE,TRUE,CONST}, which are good
for options that don't parse an argument; their presence is enough.  I
don't know if that applies to qdev.  I also include help text in each
macro, which proves to be quite nice in several contexts including --help:

    OPTION_UNSIGNED_RANGE("port", opt_port, 0, 65535,
            "the port number to listen on, from 0 to 65535")

Unfortunately although I did find expressions which say if something
is signed or a floating-point value, and evaluate to a constant at
compile time, they aren't "compile-time constant expressions" and so
cannot be used in global initialisers in standard C.  They look like:

#define is_signed(var) ((var) * 0 - 1 < 0)

-- Jamie

ps. Code to store parsed value in arbitrarily sized integer variables:

/* Store an option's value in the option's destination variable, for any
   standard integer or data pointer variable.  The value is expected to
   be appropriate and within range for the destination variable's type. */

static void
option_store_value (const struct option * option, uintmax_t value)
{
  if (option->option_var_ptr != 0)
    {
      char * var_ptr = (char *) option->option_var_ptr;
      const char * value_ptr = (const char *) &value;
      size_t p, size = option->option_var_size;

#ifdef LIBJL_LITTLE_ENDIAN
      /* Nothing to do. */
#else
# ifdef LIBJL_BIG_ENDIAN
      value_ptr += sizeof (value) - size;
# else
#  ifdef LIBJL_PDP_ENDIAN
      value_ptr += (sizeof (value) - size) & ~(size_t)1;
#  else
      /* Should work with any reasonable byte order, even complicated
         ones like 3412 (PDP, VAX) and 43218765 (ARM GCC before 2.8),
         and even when they aren't 8-bit bytes. */
      if (size < sizeof (uintmax_t))
        {
          uintmax_t order = ((uintmax_t) 1 << (size * BITS_PER_BYTE)) - 1;
          const char * order_ptr = (const char *) &order;
          for (p = 0; p < size; p++)
            if (order_ptr [p] != 0)
              break;
          value_ptr += p;
        }
#  endif
# endif
#endif
      for (p = 0; p < size; p++)
        var_ptr [p] = value_ptr [p];
    }
}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]