diff --git a/Doc/library/struct.rst b/Doc/library/struct.rst index d0960edf454..8a9d2ae18dd 100644 --- a/Doc/library/struct.rst +++ b/Doc/library/struct.rst @@ -77,7 +77,7 @@ Python values should be obvious given their types: +--------+-------------------------+--------------------+-------+ | ``B`` | :ctype:`unsigned char` | integer | | +--------+-------------------------+--------------------+-------+ -| ``t`` | :ctype:`_Bool` | bool | \(1) | +| ``?`` | :ctype:`_Bool` | bool | \(1) | +--------+-------------------------+--------------------+-------+ | ``h`` | :ctype:`short` | integer | | +--------+-------------------------+--------------------+-------+ @@ -110,7 +110,7 @@ Python values should be obvious given their types: Notes: (1) - The ``'t'`` conversion code corresponds to the :ctype:`_Bool` type defined by + The ``'?'`` conversion code corresponds to the :ctype:`_Bool` type defined by C99. If this type is not available, it is simulated using a :ctype:`char`. In standard mode, it is always represented by one byte. @@ -158,7 +158,7 @@ may be used. For example, the Alpha and Merced processors use 64-bit pointer values, meaning a Python long integer will be used to hold the pointer; other platforms use 32-bit pointers and will use a Python integer. -For the ``'t'`` format character, the return value is either :const:`True` or +For the ``'?'`` format character, the return value is either :const:`True` or :const:`False`. When packing, the truth value of the argument object is used. Either 0 or 1 in the native or standard bool representation will be packed, and any non-zero value will be True when unpacking. diff --git a/Lib/ctypes/__init__.py b/Lib/ctypes/__init__.py index b7b2a58a0f2..7cacdd2f851 100644 --- a/Lib/ctypes/__init__.py +++ b/Lib/ctypes/__init__.py @@ -240,7 +240,7 @@ c_voidp = c_void_p # backwards compatibility (to a bug) _check_size(c_void_p) class c_bool(_SimpleCData): - _type_ = "t" + _type_ = "?" # This cache maps types to pointers to them. _pointer_type_cache = {} diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py index 925308d46a5..d2261155277 100644 --- a/Lib/test/test_struct.py +++ b/Lib/test/test_struct.py @@ -84,8 +84,8 @@ sz = struct.calcsize('i') if sz * 3 != struct.calcsize('iii'): raise TestFailed, 'inconsistent sizes' -fmt = 'cbxxxxxxhhhhiillffdt' -fmt3 = '3c3b18x12h6i6l6f3d3t' +fmt = 'cbxxxxxxhhhhiillffd?' +fmt3 = '3c3b18x12h6i6l6f3d3?' sz = struct.calcsize(fmt) sz3 = struct.calcsize(fmt3) if sz * 3 != sz3: @@ -111,7 +111,7 @@ d = 3.1415 t = True for prefix in ('', '@', '<', '>', '=', '!'): - for format in ('xcbhilfdt', 'xcBHILfdt'): + for format in ('xcbhilfd?', 'xcBHILfd?'): format = prefix + format if verbose: print "trying:", format @@ -160,11 +160,11 @@ tests = [ ('f', -2.0, '\300\000\000\000', '\000\000\000\300', 0), ('d', -2.0, '\300\000\000\000\000\000\000\000', '\000\000\000\000\000\000\000\300', 0), - ('t', 0, '\0', '\0', 0), - ('t', 3, '\1', '\1', 1), - ('t', True, '\1', '\1', 0), - ('t', [], '\0', '\0', 1), - ('t', (1,), '\1', '\1', 1), + ('?', 0, '\0', '\0', 0), + ('?', 3, '\1', '\1', 1), + ('?', True, '\1', '\1', 0), + ('?', [], '\0', '\0', 1), + ('?', (1,), '\1', '\1', 1), ] for fmt, arg, big, lil, asy in tests: @@ -633,13 +633,13 @@ def test_bool(): false = (), [], [], '', 0 true = [1], 'test', 5, -1, 0xffffffffL+1, 0xffffffff/2 - falseFormat = prefix + 't' * len(false) + falseFormat = prefix + '?' * len(false) if verbose: print 'trying bool pack/unpack on', false, 'using format', falseFormat packedFalse = struct.pack(falseFormat, *false) unpackedFalse = struct.unpack(falseFormat, packedFalse) - trueFormat = prefix + 't' * len(true) + trueFormat = prefix + '?' * len(true) if verbose: print 'trying bool pack/unpack on', true, 'using format', trueFormat packedTrue = struct.pack(trueFormat, *true) @@ -658,10 +658,10 @@ def test_bool(): raise TestFailed('%r did not unpack as false' % t) if prefix and verbose: - print 'trying size of bool with format %r' % (prefix+'t') - packed = struct.pack(prefix+'t', 1) + print 'trying size of bool with format %r' % (prefix+'?') + packed = struct.pack(prefix+'?', 1) - if len(packed) != struct.calcsize(prefix+'t'): + if len(packed) != struct.calcsize(prefix+'?'): raise TestFailed('packed length is not equal to calculated size') if len(packed) != 1 and prefix: @@ -670,7 +670,7 @@ def test_bool(): print 'size of bool in native format is %i' % (len(packed)) for c in '\x01\x7f\xff\x0f\xf0': - if struct.unpack('>t', c)[0] is not True: + if struct.unpack('>?', c)[0] is not True: raise TestFailed('%c did not unpack as True' % c) test_bool() diff --git a/Misc/NEWS b/Misc/NEWS index 8d0dc795115..75d3cc104c0 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -18,6 +18,9 @@ Core and builtins Library ------- +- Issue #1872: The struct module typecode for _Bool has been changed + from 't' to '?'. + - The bundled libffi copy is now in sync with the recently released libffi3.0.4 version, apart from some small changes to Modules/_ctypes/libffi/configure.ac. diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 4ef39472e13..ea7e40d4b59 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1242,7 +1242,7 @@ _type_ attribute. */ -static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOvtg"; +static char *SIMPLE_TYPE_CHARS = "cbBhHiIlLdfuzZqQPXOv?g"; static PyObject * c_wchar_p_from_param(PyObject *type, PyObject *value) diff --git a/Modules/_ctypes/_ctypes_test.c b/Modules/_ctypes/_ctypes_test.c index d9e49641575..3f13180e0ac 100644 --- a/Modules/_ctypes/_ctypes_test.c +++ b/Modules/_ctypes/_ctypes_test.c @@ -25,6 +25,15 @@ /* some functions handy for testing */ +EXPORT(void)testfunc_array(int values[4]) +{ + printf("testfunc_array %d %d %d %d\n", + values[0], + values[1], + values[2], + values[3]); +} + EXPORT(long double)testfunc_Ddd(double a, double b) { long double result = (long double)(a * b); diff --git a/Modules/_ctypes/cfield.c b/Modules/_ctypes/cfield.c index 155e75efa44..3fd77567931 100644 --- a/Modules/_ctypes/cfield.c +++ b/Modules/_ctypes/cfield.c @@ -726,7 +726,7 @@ vBOOL_get(void *ptr, Py_ssize_t size) #endif static PyObject * -t_set(void *ptr, PyObject *value, Py_ssize_t size) +bool_set(void *ptr, PyObject *value, Py_ssize_t size) { switch (PyObject_IsTrue(value)) { case -1: @@ -741,7 +741,7 @@ t_set(void *ptr, PyObject *value, Py_ssize_t size) } static PyObject * -t_get(void *ptr, Py_ssize_t size) +bool_get(void *ptr, Py_ssize_t size) { return PyBool_FromLong((long)*(BOOL_TYPE *)ptr); } @@ -1645,15 +1645,15 @@ static struct fielddesc formattable[] = { { 'v', vBOOL_set, vBOOL_get, &ffi_type_sshort}, #endif #if SIZEOF__BOOL == 1 - { 't', t_set, t_get, &ffi_type_uchar}, /* Also fallback for no native _Bool support */ + { '?', bool_set, bool_get, &ffi_type_uchar}, /* Also fallback for no native _Bool support */ #elif SIZEOF__BOOL == SIZEOF_SHORT - { 't', t_set, t_get, &ffi_type_ushort}, + { '?', bool_set, bool_get, &ffi_type_ushort}, #elif SIZEOF__BOOL == SIZEOF_INT - { 't', t_set, t_get, &ffi_type_uint, I_set_sw, I_get_sw}, + { '?', bool_set, bool_get, &ffi_type_uint, I_set_sw, I_get_sw}, #elif SIZEOF__BOOL == SIZEOF_LONG - { 't', t_set, t_get, &ffi_type_ulong, L_set_sw, L_get_sw}, + { '?', bool_set, bool_get, &ffi_type_ulong, L_set_sw, L_get_sw}, #elif SIZEOF__BOOL == SIZEOF_LONG_LONG - { 't', t_set, t_get, &ffi_type_ulong, Q_set_sw, Q_get_sw}, + { '?', bool_set, bool_get, &ffi_type_ulong, Q_set_sw, Q_get_sw}, #endif /* SIZEOF__BOOL */ { 'O', O_set, O_get, &ffi_type_pointer}, { 0, NULL, NULL, NULL}, diff --git a/Modules/_struct.c b/Modules/_struct.c index 8e5420c7f7e..e5fe211f298 100644 --- a/Modules/_struct.c +++ b/Modules/_struct.c @@ -799,7 +799,7 @@ static formatdef native_table[] = { {'q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_longlong, np_longlong}, {'Q', sizeof(PY_LONG_LONG), LONG_LONG_ALIGN, nu_ulonglong,np_ulonglong}, #endif - {'t', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool}, + {'?', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool}, {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p}, @@ -1036,7 +1036,7 @@ static formatdef bigendian_table[] = { {'L', 4, 0, bu_uint, bp_uint}, {'q', 8, 0, bu_longlong, bp_longlong}, {'Q', 8, 0, bu_ulonglong, bp_ulonglong}, - {'t', 1, 0, bu_bool, bp_bool}, + {'?', 1, 0, bu_bool, bp_bool}, {'f', 4, 0, bu_float, bp_float}, {'d', 8, 0, bu_double, bp_double}, {0} @@ -1255,7 +1255,7 @@ static formatdef lilendian_table[] = { {'L', 4, 0, lu_uint, lp_uint}, {'q', 8, 0, lu_longlong, lp_longlong}, {'Q', 8, 0, lu_ulonglong, lp_ulonglong}, - {'t', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep, + {'?', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep, but potentially different from native rep -- reuse bx_bool funcs. */ {'f', 4, 0, lu_float, lp_float}, {'d', 8, 0, lu_double, lp_double},