ecvt(3)

✨ ecvt(3) β€” Library Functions Manual ✨

okay bestie, gather round, because today we're talking about ecvt and fcvt β€” two little float-to-string converters from the Standard C library (libc, link with -lc) that are, and I cannot stress this enough, deprecated πŸ’€. They still exist, they still work, but the vibes are very "your cool aunt who still uses LimeWire." Let's get into it 🫢


🌸 NAME 🌸

ecvt, fcvt β€” convert a floating-point number to a string πŸ’…

πŸ“š LIBRARY πŸ“š

Standard C library (libc, -lc) β€” the classic, the icon, the one you link against without even thinking about it.

πŸŽ€ SYNOPSIS πŸŽ€

#include <stdlib.h>

[[deprecated]] char *ecvt(double number, int ndigits,
                          int *restrict decpt, int *restrict sign);
[[deprecated]] char *fcvt(double number, int ndigits,
                          int *restrict decpt, int *restrict sign);

not the [[deprecated]] attribute just sitting right there in the signature 😭 the compiler is literally telling you to your face. anyway.

πŸ¦‹ Feature Test Macro Requirements for glibc πŸ¦‹

(peep feature_test_macros(7) if you're like "what is a feature test macro bestie")

ecvt(), fcvt():

  • Since glibc 2.17:
(_XOPEN_SOURCE >= 500 && ! (_POSIX_C_SOURCE >= 200809L))
    || /* glibc >= 2.20 */ _DEFAULT_SOURCE
    || /* glibc <= 2.19 */ _SVID_SOURCE
  • glibc 2.12 to glibc 2.16:
(_XOPEN_SOURCE >= 500 && ! (_POSIX_C_SOURCE >= 200112L))
    || _SVID_SOURCE
  • Before glibc 2.12:
_SVID_SOURCE || _XOPEN_SOURCE >= 500

copy that exactly, do not freestyle it, it's giving very specific πŸ’€

πŸ’– DESCRIPTION πŸ’–

so ecvt() takes your number and turns it into a null-terminated string of ndigits digits β€” except, plot twist, ndigits gets reduced down to a system-specific limit that's decided by the precision of a double. and then it hands you back a pointer to that string. ✨

some deets you need to know, no cap:

  • the high-order digit is nonzero, unless number is zero (in which case, fair enough).
  • the low order digit is rounded πŸ”₯
  • the string does not contain a decimal point β€” like, at all. the decimal point is simply not there.
  • instead, where the decimal point would be, relative to the start of the string, gets stashed in *decpt.
  • if *decpt is negative, that means the decimal point is to the left of the start of the string (so like, very smol number energy).
  • if the sign of number is negative, *sign gets set to a nonzero value. otherwise it's set to 0.
  • if number is zero, it is unspecified whether *decpt is 0 or 1. unspecified bestie. don't count on it. πŸ™ˆ

as for fcvt()? it's identical to ecvt(), except ndigits means the number of digits after the decimal point. that's the whole difference. that's it. slay.

πŸ‘‘ RETURN VALUE πŸ‘‘

both ecvt() and fcvt() return a pointer to a static string containing the ASCII representation of number.

and here's the part where you go 😭: the static string is overwritten by each call to ecvt() or fcvt(). like, every single call. it's the same string. it's always the same string. copy it out before you call again, bestie, i am begging.

🧚 ATTRIBUTES 🧚

for the deets on what all this terminology means, go read attributes(7) β€” that's the source, i'm just the messenger 🫢

  • ecvt() β€” Thread safety: MT-Unsafe race:ecvt
  • fcvt() β€” Thread safety: MT-Unsafe race:fcvt
translation: these are not thread safe, and it's not even a subtle kind of not-thread-safe. it's a whole race. if two threads call these at the same time and you expected sensible output, that's on you, not on them πŸ’€

🌈 STANDARDS 🌈

None. that's it. that's the whole section. none. zero. nothing. she's unstandardized, she's free, she's living her truth πŸ¦‹

⭐ HISTORY ⭐

  • SVr2 was where she was born πŸŽ€
  • marked as LEGACY in POSIX.1-2001
  • POSIX.1-2008 straight up removes the specifications of ecvt() and fcvt(), and instead recommends you use sprintf(3) (though snprintf(3) may be preferable β€” and honestly yeah, use the bounds-checked one, we've all been there) πŸ™ˆ

πŸ’œ NOTES πŸ’œ

not all locales use a point as the radix character ("decimal point") 🌍 β€” so don't assume it's always gonna be a . out there in the wild. check your locale. (that's setlocale(3), see below πŸ‘‡)

πŸ”₯ SEE ALSO πŸ”₯


and that's the whole page, bestie πŸ’… this was Linux man-pages 6.20, dated 2026-02-08 β€” go forth, convert your floats, but maybe use snprintf(3) instead, i'm just saying 🫢✨

πŸ“¦ 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