strtoul(3)

๐Ÿ’– strtoul(3) โ€” the "string to unsigned long int" glow-up ๐Ÿ’–

okay bestie, so this page lives in the Library Functions Manual, and honestly? it's giving "I convert your text into numbers and I do NOT miss." let's get into it ๐Ÿซถ


โœจ NAME โœจ

strtoul, strtoull, strtouq โ€” string to unsigned long int, aka the trio that turns your cute little character strings into big unsigned numbers ๐Ÿ’…


๐Ÿ“š LIBRARY ๐Ÿ“š

Standard C library... which is libc, and you link it with -lc. iconic, we love a foundational queen ๐Ÿ‘‘


๐ŸŒธ SYNOPSIS ๐ŸŒธ

#include <stdlib.h>

unsigned long strtoul(const char *restrict nptr,
                      char **_Nullable restrict endptr, int base);
unsigned long long strtoull(const char *restrict nptr,
                      char **_Nullable restrict endptr, int base);

๐Ÿงš Feature Test Macro Requirements for glibc (see feature_test_macros(7)):

strtoull():

_ISOC99_SOURCE
    || /* glibc <= 2.19: */ _SVID_SOURCE || _BSD_SOURCE
ngl the whole "define a macro before you get the function" thing is so glibc-coded. _ISOC99_SOURCE is your main character here, and if you're on glibc <= 2.19 you can also slide in with _SVID_SOURCE or _BSD_SOURCE. periodt.

๐Ÿ’ซ DESCRIPTION ๐Ÿ’ซ

So strtoul() takes the initial part of the string sitting in nptr and converts it into an unsigned long value, according to the base you hand it. that base has to be between 2 and 36 inclusive, OR it can be the special value 0. no in-between "3.5" nonsense, bestie ๐Ÿ™ˆ

Here's the vibe of what the string is allowed to look like: it may start with an arbitrary amount of white space (as determined by isspace(3)), and then a single optional '+' or '-' sign. very demure. very mindful.

Now for the base detective work, and this part is important so pay attention ๐Ÿ˜ญ:

  • if base is zero or 16, the string may then include a "0x" or "0X" prefix, and the number will be read in base 16 ๐Ÿ”ฅ
  • if base is zero or 2, the string may then include a "0b" or "0B" prefix, and the number will be read in base 2 ๐Ÿฆ‹
  • otherwise, a zero base is taken as 10 (decimal) unless the next character is '0', in which case it is taken as 8 (octal) ๐ŸŒˆ

The rest of the string gets converted to an unsigned long value "in the obvious manner" (their words, and honestly? fair), and it stops at the first character which is not a valid digit in the given base. for bases above 10, the letter 'A' in either uppercase or lowercase represents 10, 'B' represents 11, and so on and so forth, with 'Z' representing 35. that's the whole alphabet being drafted into number duty, we love range ๐Ÿ’œ

Now, the endptr tea โ˜• โ€” if endptr is not NULL, and the base is supported, strtoul() stores the address of the first invalid character in *endptr. but if there were no digits at all, strtoul() stores the original value of nptr in *endptr (and returns 0). and here's the little gotcha to remember: in particular, if *nptr is not '\0' but **endptr is '\0' on return, then the entire string is valid. chef's kiss ๐Ÿ‘‘

And strtoull()? it works just like strtoul() but returns an unsigned long long value. same energy, bigger number. ๐Ÿ’…


๐Ÿ”ฅ RETURN VALUE ๐Ÿ”ฅ

strtoul() returns either the result of the conversion, OR โ€” if there was a leading minus sign โ€” the negation of the result of the conversion represented as an unsigned value. the exception (and there's always an exception, sigh): unless the original (nonnegated) value would overflow, and in that case strtoul() returns ULONG_MAX and sets errno to ERANGE. ๐Ÿ˜ญ

Precisely the same holds for strtoull() โ€” just with ULLONG_MAX instead of ULONG_MAX. ๐Ÿ’–


๐ŸŽ€ ERRORS ๐ŸŽ€

  • This function does not modify errno on success. so if you see a change in there, something else did it, bestie, don't blame us โœจ
  • EINVAL (not in C99) โ€” the given base contains an unsupported value.
  • ERANGE โ€” the resulting value was out of range.
  • The implementation may also set errno to EINVAL in case no conversion was performed (no digits seen, and 0 returned). ๐Ÿ™ˆ

๐Ÿ‘‘ ATTRIBUTES ๐Ÿ‘‘

For an explanation of the terms used in this section, see attributes(7). (the original lays this out as a whole table, but here it is in bullet form so it's easier on your eyes, bestie ๐Ÿซถ)

  • strtoul(), strtoull(), strtouq() โ€” Thread safety: MT-Safe locale ๐ŸŒˆ

๐Ÿฆ‹ VERSIONS ๐Ÿฆ‹

In locales other than the "C" locale, other strings may be accepted. for example, the thousands separator of the current locale may be supported. so yes, your locale can lowkey change what counts as a valid number. wild, I know ๐Ÿ’€

BSD also has:

u_quad_t strtouq(const char *nptr, char **endptr, int base);

with a completely analogous definition. depending on the wordsize of the current architecture, this may be equivalent to strtoull() or to strtoul(). so it's giving "who am I today? depends on the architecture" ๐Ÿงš


โญ STANDARDS โญ

C23, POSIX.1-2024. certified, stamped, approved ๐Ÿ’…


๐Ÿ’œ HISTORY ๐Ÿ’œ

  • strtoul() โ€” POSIX.1-2001, C89, SVr4.
  • strtoull() โ€” POSIX.1-2001, C99.
  • "0b", "0B" โ€” C23. glibc 2.38. (Not in POSIX.)

๐ŸŒธ CAVEATS ๐ŸŒธ

okay this one's the classic trap and I need you to hear me ๐Ÿ˜ญ since strtoul() can legitimately return 0 or ULONG_MAX (ULLONG_MAX for strtoull()) on both success and failure, the calling program should set errno to 0 before the call, and then determine if an error occurred by checking whether errno has a nonzero value after the call. don't skip the pre-call reset, bestie, it's literally the whole plot ๐Ÿซถ


โš ๏ธ BUGS โš ๏ธ

๐Ÿ’€ Signed numbers

Some negative values are considered valid input and are silently converted to unsigned long. silently! no warning, no drama, just vibes ๐Ÿ˜ญ

๐Ÿ’€ White space

These functions silently accept leading whitespace. yep. more silent behavior. ๐Ÿ™ˆ

๐Ÿ’€ isalnum(3)

To reject white space and/or a sign, call isalnum(3) before strtoul(). that's the move ๐ŸŒŸ


๐ŸŒˆ EXAMPLES ๐ŸŒˆ

See the example on the strtol(3) manual page โ€” the use of the functions described in this manual page is similar. go peek, bestie, it's the same energy ๐Ÿ’–


๐ŸŽ€ SEE ALSO ๐ŸŽ€

a64l(3), atof(3), atoi(3), atol(3), strtod(3), strtol(3), strtoumax(3)


and that's the whole page, no cap ๐Ÿ’… this absolute icon of a man page comes to you from Linux man-pages 6.20, dated 2026-07-26 โ€” stan a consistent release schedule, periodt โœจ๐Ÿซถ

๐Ÿ“ฆ where this page comes from
  • arch rolling: man-pages 6.20-1 ยท BSD-2-Clause AND BSD-3-Clause AND BSD-4.3TAHOE AND BSD-4-Clause-UC AND GPL-1.0-or-later AND GPL-2.0-only AND GPL-2.0-or-later AND GPL-3.0-or-later AND LGPL-3.0-linking-exception AND LGPL-3.0-or-later AND LicenseRef-Public-Domain AND LicenseRef-UltraPermissive AND Linux-man-pages-1-para AND Linux-man-pages-copyleft AND Linux-man-pages-copyleft-2-para AND Linux-man-pages-copyleft-var AND MIT AND Spencer-94
  • nixpkgs unstable: man-pages 6.20
  • ๐Ÿ“œ the page's license: Linux-man-pages-copyleft
  • ๐Ÿ’– girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms