From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1MSicx-0008SJ-Iy for qemu-devel@nongnu.org; Sun, 19 Jul 2009 22:29:19 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1MSics-0008Ob-Dh for qemu-devel@nongnu.org; Sun, 19 Jul 2009 22:29:18 -0400 Received: from [199.232.76.173] (port=53609 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1MSics-0008OY-5Q for qemu-devel@nongnu.org; Sun, 19 Jul 2009 22:29:14 -0400 Received: from mail2.shareable.org ([80.68.89.115]:36952) by monty-python.gnu.org with esmtps (TLS-1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1MSicr-0006d5-LK for qemu-devel@nongnu.org; Sun, 19 Jul 2009 22:29:14 -0400 Date: Mon, 20 Jul 2009 03:29:05 +0100 From: Jamie Lokier Subject: Re: [Qemu-devel] [PATCH 2/2] Introduce macro for defining qdev properties Message-ID: <20090720022905.GB28197@shareable.org> References: <1247841685-18495-1-git-send-email-aliguori@us.ibm.com> <4A60D981.5030008@us.ibm.com> <200907172358.43108.paul@codesourcery.com> <20090718124349.GA9677@shareable.org> <4A61F498.6060208@codemonkey.ws> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <4A61F498.6060208@codemonkey.ws> List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: Anthony Liguori Cc: Blue Swirl , Anthony Liguori , Gerd Hoffman , Paul Brook , qemu-devel@nongnu.org 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 *) ℴ 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]; } }