Scott David Daniels wrote: > ... (PyObject*) (void *) &PyRange_Type, ... > Says a pointer to PyRange_Type should have the structure of a pointer > PyObject. Since the prelude to PyTypeObject matches that of PyObject, > this should be an effective cast.
The C standard says it's undefined behaviour. The compiler is free to layout PyObject entirely different from PyTypeObject, and dereferencing a PyTypeObject through a PyObject* is undefined behaviour. Python does this all the time, and it did not cause much problems in the past, but that all still does not make it defined behaviour. In particular, gcc now starts to assume (rightfully) that a PyTypeObject* and a PyObject* possibly cannot refer to the same memory when being dereferenced (hence the warning about aliasing). That means that the compiler does not need to re-read contents of one of them (e.g. the reference count) even if the memory gets changed through the other pointer. That may cause bad code to be generated (if the pointers actually do alias). The only well-defined way to alias between types in this context is that a pointer to a struct may alias with a pointer to its first member. So if PyTypeObject was defined as struct PyTypeObject { PyObject _ob; Py_ssize_t ob_size; const char *tp_name; ... }; then Python's behaviour would be well-defined (i.e. one could dereference the _ob member through a PyObject*). > Do not mistake this for advocacy of changing Python's macros; I was > telling the OP how he could shut up the complaint he was getting. In > C extensions I'd be likely to do the "convert through void *" trick > myself. And risk that the compiler generates bad code. In most cases, the compiler cannot detect that a program breaks the standard C aliasing rules. However, in some cases, it can, and in these cases, it issues a warning to make the programmer aware that the program might be full of errors (such as Python). It's unfortunate that people silence the warnings before understanding them. Regards, Martin P.S. As for an example where the compiler really does generate bad code: consider #include <stdio.h> long f(int *a, long *d){ (*d)++; *a = 5; return *d; } int main() { long d = 0; printf("%ld\n", f((int*)&d, &d)); return 0; } Here, d starts out as 0, then gets incremented (to 1) in f. Then, a value of 5 is assigned through a (which also points to d), and then the value of d (through the pointer) is printed. Without optimization, gcc 4.1 generates code that prints 5. With optimization, the compiler recognizes that d and a cannot alias, so that it does not need to refetch *d at the end of f (it still has the value in a register). So it does not reread the value, and instead returns the old value (1), and prints that. In calling f, the compiler notices that undefined behavior is invoked, and generates the warning. Casting through void* silences the warning; the generated code is still "incorrect" (of course, it's undefined, so anything is "correct"). _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com