Kevin J. Chase Kevin J. Chase - 3 years ago 247
C Question

Is the max value of size_t (SIZE_MAX) defined relative to the other integer types?

I'm writing a library of functions that will safely convert between various numeric types or die trying.
My intent is roughly equal parts create-useful-library and learn-C-edge-cases.

My

int
-to-
size_t
function is triggering a GCC
-Wtype-limits
warning that claims I shouldn't test if an
int
is greater than
SIZE_MAX
, because it will never be true.
(Another function that converts
int
to
ssize_t
produces an identical warning about
SSIZE_MAX
.)

My MCVE, with extra comments and baby steps, is:

#include <stdint.h> /* SIZE_MAX */
#include <stdlib.h> /* exit EXIT_FAILURE size_t */

extern size_t i2st(int value) {
if (value < 0) {
exit(EXIT_FAILURE);
}
// Safe to cast --- not too small.
unsigned int const u_value = (unsigned int) value;
if (u_value > SIZE_MAX) { /* Line 10 */
exit(EXIT_FAILURE);
}
// Safe to cast --- not too big.
return (size_t) u_value;
}


The Compiler Warnings



I'm getting similar warnings from GCC 4.4.5 on Linux 2.6.34:

$ gcc -std=c99 -pedantic -Wall -Wextra -c -o math_utils.o math_utils.c

math_utils.c: In function ‘i2st’:
math_utils.c:10: warning: comparison is always false due to limited range of data type


...and also from GCC 4.8.5 on Linux 3.10.0:

math_utils.c: In function ‘i2st’:
math_utils.c:10:5: warning: comparison is always false due to limited range of data type [-Wtype-limits]
if (u_value > SIZE_MAX) { /* Line 10 */
^


These warnings don't appear justified to me, at least not in the general case.
(I don't deny that the comparison might be
"always false"
on some particular combination of hardware and compiler.)

The C Standard



The C 1999 standard does not appear to rule out an
int
being greater than
SIZE_MAX
.

Section
"6.5.3.4 The
sizeof
operator"
doesn't address
size_t
at all, except to describe it as
"defined in
<stddef.h>
(and other headers)".

Section
"7.17 Common definitions
<stddef.h>
"
defines
size_t
as
"the unsigned integer type of the result of the
sizeof
operator".
(Thanks, guys!)

Section
"7.18.3 Limits of other integer types"
is more helpful ---
it defines
"limit of
size_t
" as:


SIZE_MAX
65535



...meaning
SIZE_MAX
could be as small as 65535.
An
int

(signed or unsigned)
could be much greater than that, depending on the hardware and compiler.

Stack Overflow



The accepted answer to
"
unsigned int
vs.
size_t
"
seems to support my interpretation
(emphasis added):


The
size_t
type may be bigger than, equal to, or smaller than an
unsigned int
, and your compiler might make assumptions about it for optimization.


This answer cites the same
"Section 7.17"
of the C standard that I've already quoted.

Other Documents



My searches turned up the Open Group's paper
"Data Size Neutrality and 64-bit Support",
which claims under
"64-bit Data Models"
(emphasis added):


ISO/IEC 9899:1990, Programming Languages - C (ISO C)
left the definition of the
short int
, the
int
, the
long int
, and the
pointer
deliberately vague
[...]
The only constraints were that
int
s must be no smaller than
short
s, and
long
s must be no smaller than
int
s, and
size_t
must represent the largest unsigned type supported by an implementation
.
[...]
The relationship between the fundamental data types can be expressed as:


sizeof(char)
<=
sizeof(short)
<=
sizeof(int)
<=
sizeof(long)
=
sizeof(size_t)




If this is true, then testing an
int
against
SIZE_MAX
is indeed futile...
but this paper doesn't cite chapter-and-verse, so I can't tell how its authors reached their conclusion.
Their own
"Base Specification Version 7"
sys/types.h
docs

don't address this either way.

My Question



I understand that
size_t
is unlikely to be narrower than an
int
, but does the C standard guarantee that comparing
some_unsigned_int > SIZE_MAX
will always be false?
If so, where?

Not-Duplicates



There are two semi-duplicates of this question, but they are both asking more general questions about what
size_t
is supposed to represent and when it should / should-not be used.


  • "What is
    size_t
    in C?
    "
    does not address the relationship between
    size_t
    and the other integer types.
    Its accepted answer is just a quote from Wikipedia, which doesn't provide any information beyond what I've already found.

  • "What is the correct definition of
    size_t
    ?
    "
    starts off nearly a duplicate of my question, but then veers off course, asking
    when
    size_t
    should be used and why it was introduced.
    It was closed as a duplicate of the previous question.


Answer Source

The current C standard does not require size_t to be no narrower than an int, and I'm skeptical about any version of the standard ever doing so. size_t needs to be able to represent any number which might be the size of an object; if the implementation limits object sizes to be 24 bits wide, then size_t could be a 24-bit unsigned type, regardless of what an int is.

The GCC warning does not refer to theoretical possibilities. It is checking a particular hardware platform and a particular compiler and runtime. That means it sometimes triggers on code which is trying to be portable. (There are other cases where portable code will trigger optional GCC warnings.) That might not be what you were hoping the warning would do, but there are probably users whose expectations are precisely matched by the implemented behaviour, and the standard provides no guidelines whatsoever for compiler warnings.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download