Programming Pointers

Standard C's pointer difference type

Dan Saks

10/18/2007 4:27 PM EDT

Though not as useful and prevalent as size_t, ptrdiff_t is still worth a look.

I recently wrote a couple of columns in which I explained why the Standard C and C++ libraries define a typedef named size_t. The type size_t is an alias for whichever unsigned integer type is the result of the sizeof operator. It corresponds to the smallest unsigned integer type capable of representing the size of the largest possible object in the target environment. Depending on the target, size_t might be an alias for unsigned, for unsigned long, or for unsigned long long.

In response to those columns, a few readers suggested that ssize_t is a useful alternative to size_t. Some C libraries define ssize_t as a signed integer type that has the same size as size_t. Inasmuch as ssize_t isn't part of Standard C (or Standard C++), I don't recommend using it unless you need it to communicate with a library that provides its own ssize_t. Instead, I recommend using ptrdiff_t.

Standard C provides the odd-sounding typedef ptrdiff_t (pronounced PUT-er-diff-TEE) as the signed counterpart to size_t. Although the standard offers no explicit guarantee that sizeof(ptrdiff_t) equals sizeof(size_t), I have yet to use a compiler for which this isn't so.

In truth, the C standard doesn't define ptrdiff_t as having any direct relationship to size_t. Rather, it defines ptrdiff_t as the signed integer type of the result of subtracting two pointers. For example, given:

T *p, *q;

for any non-void type T, you can write expressions such as:

d = p - q;

If you declare d as:

ptrdiff_t d;

then the assignment above should behave properly when compiled with any Standard C compiler. If you were to declare d as some other integer type, such as:

int d;

then the assignment might provoke a warning from the compiler, or worse, silently truncate the assigned value at run time.

Whereas numerous functions of the Standard C library have parameters or return values of type size_t, none has parameters or return values of type ptrdiff_t. In contrast, the Standard C++ library uses ptrdiff_t, though not as often as it uses size_t. Most of those uses appear in the generic iterator components of the standard library.

You can use printf to display a ptrdiff_t. According to the 1999 C Standard, the format string should contain the t length modifier with the d or i conversion specifier, as in:

ptrdiff_t d;
...
printf("%td", d);

Although the d specifier has been around as long as C, the t modifier is fairly new. Few C libraries support it yet.

If your compiler doesn't support %td, then you should try %ld, as in:

printf("%ld", (long)d);

Displaying a ptrdiff_t using the Standard C++ iostream library is a simple as displaying any other numeric type:

std::cout << d;

Dan Saks is president of Saks & Associates, a C/C++ training and consulting company. For more information about Dan Saks, visit his website at www.dansaks.com. Dan also welcomes your feedback: e-mail him at dsaks@wittenberg.edu. For more information about Dan click here .

1. Saks, Dan. "Why size_t matters," Embedded Systems Design, July 2007, p. 11.

2. Saks, Dan. "Further insights into size_t," Embedded Systems Design, September 2007, p. 9.





betaylor73

10/19/2007 12:42 AM EDT

In your article (embedded.com - 10/18/07) you state:

"If your compiler doesn't support %td, then you should try %ld..."

This is problematic for a system wherein the pointer-holding type is wider than a long (e.g. an I16L32LLP64 system).

You would be better off using the PRIdPTR macro. This macro should be defined as "td" for platforms that support the 't' length modifier and something like "ld" or "lld" for platforms that do not.

PRIdPTR and its related macros are described in section 7.8 of the C99 specification.

---Brandon E Taylor

Message was edited by: SRambo

Message was edited by: SRambo

Sign in to Reply



Dan Saks

10/22/2007 3:26 PM EDT

ptrdiff_t doesn't hold pointers -- it holds differences between pointers. On most platforms, a pointer and pointer difference have the same size, but as far as I can tell, no such guarantee appears in the standard.

Nonetheless, you raise a valid point about using the %ld format specifier -- casting size_t to long might truncate the result. In practice, I think you'll be hard pressed to find a compiler where this actually will be a problem, but the possibility of truncation does exist.

Using the %lld format and a cast to long long, as in:

printf("%lld", (long long)d);

might be less likely to cause a truncation, but still offers no guarantee. A Standard C implementation may define ptrdiff_t as some implementation-defined integer type larger than long long. I'm not aware of any compiler that does that, but again, it's possible.

I think PRIdMAX is a more appropriate format specifier than PRIdPTR. If you use PRIdMAX, then you should use it in conjunction with a cast to intmax_t, as in:

printf("%" PRIdMAX, (intmax_t)p);

For those unfamiliar with these symbols... PRidMAX is a macro defined in the C99 header and intmax_t is a typedef defined in the C99 header . Unfortunately, not all C compilers provide these headers.

I will probably elaborate on this discussion in an upcoming column.

Message was edited by: SRambo

Sign in to Reply



Please sign in to post comment

Navigate to related information

Datasheets.com Parts Search

185 million searchable parts
(please enter a part number or hit search to begin)
Jobs sponsored by

Feedback Form