summaryrefslogtreecommitdiffstats
path: root/src/corelib/global
diff options
context:
space:
mode:
authorGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-04-23 11:54:49 +0200
committerGiuseppe D'Angelo <giuseppe.dangelo@kdab.com>2021-04-25 15:24:45 +0200
commit5fabad9a61d7fe7eadbd602723f39514932d7eaa (patch)
tree84d27c718eb1a120c8960e9e02c828ddae81a1d5 /src/corelib/global
parent7c9597ef56f4df7bf2201a880906256b483d01c5 (diff)
Long live PRI*Qdatatypes
Qt defines some integral datatypes (qsizetype, qintptr, quintptr, qptrdiff) not in terms of the corresponding language datatypes (resp. make_signed_t<size_t>, intptr_t, uintptr_t, ptrdiff_t) but as "integer types with the same bit size of the corresponding language type" (and of course the corret correct signedness for the target type). This makes the Qt datatypes not printable via printf-like formatted output, incl. qDebug, qWarning, QString::asprintf and so on; that's because there isn't a format modifier that would universally work with the Qt definitions. For instance, on a 32 bit platform, ptrdiff_t may be a typedef for long, while qptrdiff is a typedef for _int_ instead. Both long and int would indeed be 32 bits, but they still are different types, and this means that the ptrdiff_t-specific 't' length modifier would be wrong for qptrdiff: qptrdiff p; printf("%td", p); // WARNING: -Wformat: wanted long, got int Similarly, not using 't' breaks on 64 bits, and so on and so forth. There isn't a way out, short of inserting casts on every print statement. So, let's adopt the same solution C/C++ use for their own integer typedefs: the PRIx macros. This allows one to always use the correct formatting specifier without the need of a cast. I'm not adding the macros for the qintXX datatypes, as they already exist in the Standard Library. [ChangeLog][QtCore][QtGlobal] A series of PRIxQTDATATYPE macros have been added. They make it possible to print some Qt type aliases (qsizetype, qintptr, etc.) via a formatted output facility such as printf() or qDebug() without raising formatting warnings and without the need of a type cast. Change-Id: I473226a661868aed9514d793c8e6e4d391ab5055 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io> Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
Diffstat (limited to 'src/corelib/global')
-rw-r--r--src/corelib/global/qglobal.cpp83
-rw-r--r--src/corelib/global/qglobal.h58
2 files changed, 140 insertions, 1 deletions
diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp
index 2d5e647739..a0a8d8c395 100644
--- a/src/corelib/global/qglobal.cpp
+++ b/src/corelib/global/qglobal.cpp
@@ -826,10 +826,29 @@ static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
Note that qintptr is signed. Use quintptr for unsigned values.
+ In order to print values of this type by using formatted-output
+ facilities such as \c{printf()}, qDebug(), QString::asprintf() and
+ so on, you can use the \c{PRIdQINTPTR} and \c{PRIiQINTPTR}
+ macros as format specifiers. They will both print the value as a
+ base 10 number.
+
+ \code
+ qintptr p = 123;
+ printf("The pointer is %" PRIdQINTPTR "\n", p);
+ \endcode
+
\sa qptrdiff, qint32, qint64
*/
/*!
+ \macro PRIdQINTPTR
+ \macro PRIiQINTPTR
+ \since 6.2
+
+ See qintptr.
+*/
+
+/*!
\typedef quintptr
\relates <QtGlobal>
@@ -844,10 +863,36 @@ static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
Note that quintptr is unsigned. Use qptrdiff for signed values.
+ In order to print values of this type by using formatted-output
+ facilities such as \c{printf()}, qDebug(), QString::asprintf() and
+ so on, you can use the following macros as format specifiers:
+
+ \list
+ \li \c{PRIuQUINTPTR}: prints the value as a base 10 number.
+ \li \c{PRIoQUINTPTR}: prints the value as a base 8 number.
+ \li \c{PRIxQUINTPTR}: prints the value as a base 16 number, using lowercase \c{a-f} letters.
+ \li \c{PRIXQUINTPTR}: prints the value as a base 16 number, using uppercase \c{A-F} letters.
+ \endlist
+
+ \code
+ quintptr p = 123u;
+ printf("The pointer value is 0x%" PRUXQUINTPTR "\n", p);
+ \endcode
+
\sa qptrdiff, quint32, quint64
*/
/*!
+ \macro PRUoQUINTPTR
+ \macro PRIuQUINTPTR
+ \macro PRIxQUINTPTR
+ \macro PRIXQUINTPTR
+ \since 6.2
+
+ See quintptr.
+*/
+
+/*!
\typedef qptrdiff
\relates <QtGlobal>
@@ -860,10 +905,29 @@ static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
Note that qptrdiff is signed. Use quintptr for unsigned values.
+ In order to print values of this type by using formatted-output
+ facilities such as \c{printf()}, qDebug(), QString::asprintf() and
+ so on, you can use the \c{PRIdQPTRDIFF} and \c{PRIiQPTRDIFF}
+ macros as format specifiers. They will both print the value as a
+ base 10 number.
+
+ \code
+ qptrdiff d = 123;
+ printf("The difference is %" PRIdQPTRDIFF "\n", d);
+ \endcode
+
\sa quintptr, qint32, qint64
*/
/*!
+ \macro PRIdQPTRDIFF
+ \macro PRIiQPTRDIFF
+ \since 6.2
+
+ See qptrdiff.
+*/
+
+/*!
\typedef qsizetype
\relates <QtGlobal>
\since 5.10
@@ -875,10 +939,29 @@ static_assert(sizeof(qint64) == 8, "Internal error, qint64 is misdefined");
Note that qsizetype is signed. Use \c size_t for unsigned values.
+ In order to print values of this type by using formatted-output
+ facilities such as \c{printf()}, qDebug(), QString::asprintf() and
+ so on, you can use the \c{PRIdQSIZETYPE} and \c{PRIiQSIZETYPE}
+ macros as format specifiers. They will both print the value as a
+ base 10 number.
+
+ \code
+ qsizetype s = 123;
+ printf("The size is %" PRIdQSIZETYPE "\n", s);
+ \endcode
+
\sa qptrdiff
*/
/*!
+ \macro PRIdQSIZETYPE
+ \macro PRIiQSIZETYPE
+ \since 6.2
+
+ See qsizetype.
+*/
+
+/*!
\enum QtMsgType
\relates <QtGlobal>
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index c3de245a32..1b92b5e8b6 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -45,6 +45,7 @@
# include <type_traits>
# include <cstddef>
# include <utility>
+# include <cstdint>
#endif
#ifndef __ASSEMBLER__
# include <assert.h>
@@ -248,6 +249,20 @@ typedef ptrdiff_t qptrdiff;
typedef ptrdiff_t qsizetype;
typedef ptrdiff_t qintptr;
typedef size_t quintptr;
+
+#define PRIdQPTRDIFF "td"
+#define PRIiQPTRDIFF "ti"
+
+#define PRIdQSIZETYPE "td"
+#define PRIiQSIZETYPE "ti"
+
+#define PRIdQINTPTR "td"
+#define PRIiQINTPTR "ti"
+
+#define PRIuQUINTPTR "zu"
+#define PRIoQUINTPTR "zo"
+#define PRIxQUINTPTR "zx"
+#define PRIXQUINTPTR "zX"
#endif
/*
@@ -593,7 +608,7 @@ Q_CORE_EXPORT Q_DECL_CONST_FUNCTION const char *qVersion(void) Q_DECL_NOEXCEPT;
&& sizeof(void *) == sizeof(qptrdiff)
size_t and qsizetype are not guaranteed to be the same size as a pointer, but
- they usually are.
+ they usually are. We actually check for that in qglobal.cpp.
*/
template <int> struct QIntegerForSize;
template <> struct QIntegerForSize<1> { typedef quint8 Unsigned; typedef qint8 Signed; };
@@ -611,6 +626,47 @@ typedef QIntegerForSizeof<void *>::Signed qptrdiff;
typedef qptrdiff qintptr;
using qsizetype = QIntegerForSizeof<std::size_t>::Signed;
+// These custom definitions are necessary as we're not defining our
+// datatypes in terms of the language ones, but in terms of integer
+// types that have the sime size. For instance, on a 32-bit platform,
+// qptrdiff is int, while ptrdiff_t may be aliased to long; therefore
+// using %td to print a qptrdiff would be wrong (and raise -Wformat
+// warnings), although both int and long have same bit size on that
+// platform.
+//
+// We know that sizeof(size_t) == sizeof(void *) == sizeof(qptrdiff).
+#if SIZE_MAX == 4294967295ULL
+#define PRIuQUINTPTR "u"
+#define PRIoQUINTPTR "o"
+#define PRIxQUINTPTR "x"
+#define PRIXQUINTPTR "X"
+
+#define PRIdQPTRDIFF "d"
+#define PRIiQPTRDIFF "i"
+
+#define PRIdQINTPTR "d"
+#define PRIiQINTPTR "i"
+
+#define PRIdQSIZETYPE "d"
+#define PRIiQSIZETYPE "i"
+#elif SIZE_MAX == 18446744073709551615ULL
+#define PRIuQUINTPTR "llu"
+#define PRIoQUINTPTR "llo"
+#define PRIxQUINTPTR "llx"
+#define PRIXQUINTPTR "llX"
+
+#define PRIdQPTRDIFF "lld"
+#define PRIiQPTRDIFF "lli"
+
+#define PRIdQINTPTR "lld"
+#define PRIiQINTPTR "lli"
+
+#define PRIdQSIZETYPE "lld"
+#define PRIiQSIZETYPE "lli"
+#else
+#error Unsupported platform (unknown value for SIZE_MAX)
+#endif
+
/* moc compats (signals/slots) */
#ifndef QT_MOC_COMPAT
# define QT_MOC_COMPAT