Fixing 32/64 bit semantics of long (Re: GLib and 64-bit Windows)



On Wed, 30 Jan 2008, Owen Taylor wrote:

I'm not sure what you you are asking here. What I was saying is that
changing vtable members is more likely to break things than changing
function prototypes.

Ok, but then, every prototype change can be a "vtable change", given a
custom vtable that has a slot expecting a certain glib API function type,
as in the g_realloc() pointer example.
(Yes, i realize that you were referring only to vtables exported by glib ;)

if i understand you correctly, you mean to imply that we also fix the
signatures from *long to *size as well for the following functions
(comprehensive list of *long API in glib/glib/*.h):


gdouble  g_timer_elapsed         (GTimer      *timer,
                                   gulong      *microseconds);
[...]

No, I didn't mean that, because

gdouble  g_timer_elapsed         (GTimer      *timer,
                                  size_t      *microseconds);

gulong microseconds;

g_timer_elapsed(timer, &microseconds);

Will warn in many many situations on many platforms, and MSVC will warn
about:

gsize g_utf8_strlen (const gchar *p,
                     gssize       max);

long value = g_utf8_strlen(p, max);

even when compiling for 32 bits. So I don't consider changing out
parameters and returns from long => size_t compatible.

Hmmmm...

I think it makes sense to distinguish between changing long value
types and *long pointer types. The former is unlikely to
cause major breakage. The exception being custom vtables that
expect particular prototypes in GLib and possibly return type size
warnings (though a case can be made for wanting those
warnings i think).

We currently have these semantics for GLib types wrg 32/64bit
portability:

gint32		- 32bit on all platforms
gint64		- 64bit on all platforms
glong		- 32bit on 32 bit platforms & Win64, 64bit on 64 bit platforms
gsize		- 32bit on 32 bit platforms, 64bit on 64 bit platforms
ptrdiff_t	- 32bit on 32 bit platforms, 64bit on 64 bit platforms

That is, glong is pretty much useless. If a type is needed
that reliably widens size on 64bit system (usually needed
to store pointer values or larger memory offsets/sizes),
we actually have to use gsize.

These are the possibilities i see to solve this:

1) Define glong to ssize_t on Win64. This'll break the
   assumption that long==glong on all platforms though.

2) Search+replace our headers for glong -> gssize (i.e. what
   i suggested in my previous email).

3) Introduce a new type, e.g. "gwide/guwide":
	#ifdef _WIN64
	  typedef ssize_t gwide;
	  typedef size_t  guwide;
	#else /* !_WIN64 */
	  typedef glong  gwide;
	  typedef gulong guwide;
	#endif
   Then search+replace our headers for it, i.e. glong -> gwide.
   This preserves "long"-ness on all currently existing platforms,
   and still allows the repsective API for Win64 to be 64bit wide.

Further notes:

- Deprecate usage of "long/glong" in public headers. This should
  be part of our policy in any case. Long simply has unclear
  semantics, gint32/gint64/gsize have clear semantics wrt to
  32bit/64bit platforms.
  Deprecate use of "gwide" in favor of gint32/gint64/gsize, this
  type is only needed in places where we used to have glong in
  public API for historical reasons.

- When i say "search+replace", i'm including the types used in the
  G_TYPE_LONG API, e.g. g_value_set_long().
  Changing glong->gssize or glong->gwide there might look surprising,
  but provides clear calling semantics.
  In retrospect, i shouldn't have added support for longs to GType
  in the first place...

Out of the above, i think (1) provides potentially bad pitfalls,
because it's surprisingly inconsistent with other glib types.

The ideal solution might be (2), and i think it's worth putting it
into place in a future devel branch of GLib, with the option of
falling back to (3) if (2) turns out to cause bad breakage in
practice. I.e. (3) might be needed anyway for long pointer types
as you pointed out above, but that's the minority of API changes
(11 out of 57).

Functions with long pointers:
g_timer_elapsed
g_utf8_to_utf16
g_utf8_to_ucs4
g_utf8_to_ucs4_fast
g_utf16_to_ucs4
g_utf16_to_utf8
g_ucs4_to_utf16
g_ucs4_to_utf8
gdk_colors_alloc
gdk_colors_free
GdkEventClient

Functions/structures with long arguments and return values:
GHookList
g_hook_destroy
g_hook_get
G_STRUCT_OFFSET
G_STRUCT_MEMBER_P
GOptionEntry
g_thread_create_full
g_usleep
g_time_val_add
GTimeVal
g_utf8_offset_to_pointer
g_utf8_pointer_to_offset
g_utf8_strlen
g_snprintf
g_vsnprintf
g_bit_nth_lsf
g_bit_nth_msf
g_bit_storage
g_signal_connect_object
g_param_spec_long
g_param_spec_ulong
GParamSpecLong
GParamSpecULong
g_signal_add_emission_hook
g_signal_remove_emission_hook
g_signal_connect_closure_by_id
g_signal_connect_closure
g_signal_connect_data
g_signal_handler_block
g_signal_handler_unblock
g_signal_handler_disconnect
g_signal_handler_is_connected
g_signal_handler_find
GTypeCValue
G_VALUE_COLLECT
G_VALUE_LCOPY
GValue
g_value_set_long
g_value_get_long
g_value_set_ulong
g_value_get_ulong
PangoOTFeatureMap
pango_ot_ruleset_add_feature
pango_ot_ruleset_maybe_add_feature
gdk_colormap_query_color
gdk_property_get
GdkRegion
gdk_rgb_xpixel_from_rgb
GtkBindingArg
gtk_settings_set_long_property
gtk_signal_connect_full
GtkTreeDataList
GtkArg
GTK_VALUE_LONG
GTK_VALUE_ULONG
GTK_RETLOC_LONG
GTK_RETLOC_ULONG

- Owen

---
ciaoTJ


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