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_MAX65535
...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_ttype may be bigger than, equal to, or smaller than anunsigned 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, theint, thelong int, and thepointerdeliberately vague [...] The only constraints were thatints must be no smaller thanshorts, andlongs must be no smaller thanints, andsize_tmust 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_tin C?" does not address the relationship betweensize_tand 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 whensize_tshould be used and why it was introduced. It was closed as a duplicate of the previous question.