{
  "description": "Browse aymeric's, an independent, searchable archive of readable snapshots from followed feeds, preserved in Git with aggr.",
  "feed_url": "https://aggr.aymericbeaumet.com/sources/sebsite.pw/feed.json",
  "home_page_url": "https://aggr.aymericbeaumet.com/sources/sebsite.pw/",
  "items": [
    {
      "authors": [
        {
          "name": "dverlaeckt80"
        }
      ],
      "content_html": "<p>The committee has created an unreal language that no one can or will actually use.<br />\n- <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://port70.net/~nsz/c/c89/dmr-on-noalias.html\">Dennis Ritchie</a> (out of context)</p>\n<p>this is an incomplete list of some incompatibilities between c as it's written in the standard and c as it exists in the real world for people who use gcc/clang + glibc/musl.</p>\n<h2><code>asm</code></h2>\n<p>by default, gcc and clang recognize the <code>asm</code> keyword as an extension. this is not strictly conformant, because in standard c, <code>asm</code> is a valid non-reserved identifier. so code which conforms to the standard may not compile with gcc/clang with their default settings.</p>\n<p>and like, whatever, that's fine, that's why <code>-std</code> exists, but 1. it's notable that compilers aren't conformant <em>by default</em>, and 2. why doesn't the standard just make <code>asm</code> a reserved word? c++ does that; i'm not sure why c doesn't.</p>\n<h2><code>FLT_ROUNDS</code></h2>\n<p>the standard specifies the <code>FLT_ROUNDS</code> macro in <code>float.h</code> as follows:</p>\n<p>5.3.5.3.3p23:</p>\n<blockquote>\n<p>The rounding mode for floating-point addition for standard floating types is characterized by the implementation-defined value of <code>FLT_ROUNDS</code>. Evaluation of <code>FLT_ROUNDS</code> correctly reflects any execution-time change of rounding mode through the function <code>fesetround</code> in <code>&lt;fenv.h&gt;</code>.</p>\n</blockquote>\n<p>notably, the standard requires that the value dynamically changes with the runtime floating environment. gcc, however, always defines <code>FLT_ROUNDS</code> to 1 (rounds to nearest), regardless of the runtime rounding mode:</p>\n<pre><code><span class=\"code-snippet\">/* Addition rounds to 0: zero, 1: nearest, 2: +inf, 3: -inf, -1: unknown.  */\n/* ??? This is supposed to change with calls to fesetround in &lt;fenv.h&gt;.  */\n#undef FLT_ROUNDS\n#define FLT_ROUNDS 1\n</span></code></pre>\n<p>clang defines a builtin for this (<code>__builtin_flt_rounds()</code>), but gcc doesn't, for some reason.</p>\n<h2>standard pragmas</h2>\n<p>at some point in the future i'm gonna make an entire blog post dedicated to just this, because i kinda find it fascinating. but the super duper short version is this:</p>\n<p>the c standard specifies five standard pragmas to control the behavior of floating point arithmetic:</p>\n<pre><code><span class=\"code-snippet\">// added in c99:\n// switch can be ON, OFF, or DEFAULT\n#pragma STDC FP_CONTACT ON\n#pragma STDC FENV_ACCESS ON\n#pragma STDC CX_LIMITED_RANGE ON\n\n// added in c23:\n// direction can be FE_DYNAMIC, FE_DOWNWARD, FE_TONEAREST,\n// FE_TONEARESTFROMZERO, FE_TOWARDZERO, FE_UPWARD, or some\n// other implementation-defined value\n#pragma STDC FENV_ROUND FE_DYNAMIC\n#pragma STDC FENV_DEC_ROUND FE_DYNAMIC\n</span></code></pre>\n<p>however, over 27 years after c99 was standardized, <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://gcc.gnu.org/projects/c-status.html\">gcc still doesn't support any of the standard pragmas</a>. they're just no-ops in gcc.</p>\n<p>some (but not all) of the functionality can be replicated with command-line flags, but those operate on the entire translation unit, whereas the pragmas can apply to individual functions and blocks.</p>\n<p>clang mostly supports the c99 pragmas, but still doesn't support the c23 pragmas.</p>\n<p>there's actually <em>so much</em> more to say about these. i <em>will</em> be writing more about them at some point, but rn i don't really have the motivation cuz it's such a big thing lol</p>\n<h2>qualifiers in function return types</h2>\n<p>the standard requires that qualifiers in function return types are discarded:</p>\n<blockquote>\n<p>If, in the declaration &quot;<code>T D1</code>&quot;, <code>D1</code> has the form</p>\n<pre><code><span class=\"code-snippet\">D ( parameter-type-listopt ) attribute-specifier-sequenceopt\n</span></code></pre>\n<p>and the type specified for <em>ident</em> in the declaration &quot;<code>T D</code>&quot; is &quot;<em>derived-declarator-type-list <code>T</code></em>&quot;, then the type specified for <em>ident</em> is &quot;<em>derived-declarator-type-list</em> function returning the unqualified, non-atomic version of <code>T</code>&quot;. The optional attribute specifier appertains to the function type.</p>\n</blockquote>\n<p>but clang treats them as significant:</p>\n<pre><code><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> cat t.c</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">int</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> f(</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">const</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> int f(</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span>\n</span></span></code></pre>\n<pre><code><span class=\"code-snippet\" data-language=\"Shell\"><span class=\"syntax-source syntax-shell syntax-bash\"><span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">$</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> clang t.c</span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">t.c:2:11:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> error: conflicting types for <span class=\"syntax-string syntax-quoted syntax-single syntax-shell\"><span class=\"syntax-punctuation syntax-definition syntax-string syntax-begin syntax-shell\">&#39;</span>f<span class=\"syntax-punctuation syntax-definition syntax-string syntax-end syntax-shell\">&#39;</span></span></span>\n    <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">2</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">const</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> int f(</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span>\n      <span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span>           <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">^</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">t.c:1:5:</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> note: previous declaration is here</span>\n    <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">1</span></span> <span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span> <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">int</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> f(</span><span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-meta syntax-post-cmd syntax-shell\">)</span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-continue syntax-shell\">;</span>\n      <span class=\"syntax-meta syntax-function-call syntax-shell\"></span><span class=\"syntax-keyword syntax-operator syntax-logical syntax-pipe syntax-shell\">|</span>     <span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">^</span></span>\n<span class=\"syntax-meta syntax-function-call syntax-shell\"><span class=\"syntax-variable syntax-function syntax-shell\">1</span></span><span class=\"syntax-meta syntax-function-call syntax-arguments syntax-shell\"> error generated.</span>\n</span></span></code></pre>\n<p>the two declarations should be identical, but clang thinks they're incompatible.</p>\n<h2>outdated <code>va_start</code> definition on musl</h2>\n<p>for some reason, musl provides its own versions of some headers which the compiler already provides itself. one of these is <code>stdarg.h</code>, which is required to be supported by freestanding implementations and so is virtually guaranteed to already be provided by the compiler. but because it's provided by musl, compilers will use that header instead of the builtin one.</p>\n<p>this is a problem because musl's header is strictly worse than the builtin header. here's how musl defines <code>va_start</code>:</p>\n<pre><code><span class=\"code-snippet\">#define va_start(v,l)   __builtin_va_start(v,l)\n</span></code></pre>\n<p>this definition is incorrect, because c23 allows the second argument to be omitted. it should be defined like this:</p>\n<pre><code><span class=\"code-snippet\">#if __STDC_VERSION__ &gt;= 202311L\n#define va_start(...) __builtin_c23_va_start(__VA_ARGS__)\n#else\n#define va_start(v,l) __builtin_va_start(v,l)\n#endif\n</span></code></pre>\n<p>the result is that, when compiling for musl, c23's single-argument <code>va_start</code> can't be used, even if it's supported by the compiler.</p>\n<h2>see also</h2>\n<ul>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://sebsite.pw/w/20261004-math_errhandling.html\">notes on how glibc and musl handle math errors</a> (<code>math_errhandling</code>)</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://sebsite.pw/w/20261009-strtod.html\">oh, apparently it's not possible to portably check for string-to-float conversion errors in standard c</a>: a case where posix arguably specifies a family of functions incompatibly from standard c</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://sebsite.pw/w/20260708-badstdcxx.html\">neither gcc nor clang are compliant with standard c++</a>: gcc and clang don't store language linkage information with function types in c++, contrary to what the standard requires</li>\n<li><a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://sebsite.pw/w/20261014-initstate.html\">yet another place where a linux man page is inaccurate</a> (containing a deleted section from this post!)</li>\n</ul>\n",
      "date_modified": "2026-10-13T13:36:21+00:00",
      "date_published": "2026-10-13T13:36:21+00:00",
      "external_url": "https://sebsite.pw/w/20261012-notstdc.html",
      "id": "urn:aggr:item:a1bbc7e07f353e77b8f5028c1d935f6f76ebef79",
      "summary": "The committee has created an unreal language that no one can or will actually use. - Dennis Ritchie (out of context) this is an incomplete list of some incompatibilities between c as it's written in the standard and c as it exists in the…",
      "tags": [
        "news"
      ],
      "title": "Your C is not standard C",
      "url": "https://aggr.aymericbeaumet.com/items/hnrss-org/2026-10-13-your-c-is-not-standard-c/"
    },
    {
      "authors": [
        {
          "name": "sebsite.pw by seb"
        }
      ],
      "content_html": "<p>this is kinda a sequel-ish to my <a target=\"_blank\" rel=\"noopener noreferrer\" href=\"https://sebsite.pw/w/20261004-math_errhandling.html\">previous post</a>, in which i go over the <code>math_errhandling</code> macro, and how math error handling is done in glibc and musl (as well as how it's specified in the standard).</p>\n<p>to summarize: <code>math_errhandling</code> is a macro which indicates which error-handling mechanisms are supported by <code>math.h</code> functions: <code>errno</code> (<code>MATH_ERRNO</code>) and/or floating-point exceptions (<code>MATH_ERREXCEPT</code>).</p>\n<p>there's one thing i didn't mention in my previous post: there's one family of functions which is affected by <code>math_errhandling</code> but which <em>isn't</em> in <code>math.h</code>: the string to float conversion functions <code>strtod</code>, <code>strtof</code>, <code>strtold</code>, <code>strtod32</code>, <code>strtod64</code>, and <code>strtod128</code>:</p>\n<p>7.25.2.6p12:</p>\n<blockquote>\n<p>If the correct value overflows and default rounding is in effect (7.12.2), plus or minus <code>HUGE_VAL</code>, <code>HUGE_VALF</code>, or <code>HUGE_VALL</code> is returned (according to the return type and sign of the value); if the integer expression <code>math_errhandling &amp; MATH_ERRNO</code> is nonzero, the integer expression <code>errno</code> acquires the value of <code>ERANGE</code>; if the integer expression <code>math_errhandling &amp; MATH_ERREXCEPT</code> is nonzero, the &quot;overflow&quot; floating-point exception is raised.</p>\n<p>If the result underflows (7.12.2), the functions return a value whose magnitude is no greater than the smallest normalized positive number in the return type; if the integer expression <code>math_errhandling &amp; MATH_ERRNO</code> is nonzero, whether <code>errno</code> acquires the value <code>ERANGE</code> is implementation-defined; if the integer expression <code>math_errhandling &amp; MATH_ERREXCEPT</code> is nonzero, whether the &quot;underflow&quot; floating-point exception is raised is implementation-defined.</p>\n</blockquote>\n<p>the linux man pages for these functions literally don't mention this <em>at all</em>, and there actually is a reason why which i'll get to in a sec, but what the standard is saying is, if <code>math_errhandling</code> doesn't advertise support for <code>errno</code> (as is the case on musl, for instance), the string to float conversion functions <strong>don't set <code>errno</code> on error</strong>. furthermore, if the result underflows, the function <strong>isn't required to report an error at all</strong>.</p>\n<p>keep in mind that the return value alone isn't enough to determine if an error occurred, so to test for overflow, you <em>need</em> to use one of the two error handling mechanisms.</p>\n<p>here is my attempt at a standards-blessed way of portably checking for overflow/underflow errors in the string to float functions:</p>\n<pre><code><span class=\"code-snippet\">feclearexcept(FE_OVERFLOW | FE_UNDERFLOW);\nerrno = 0;\ndouble x = strtod(s, nullptr);\nbool errored = math_errhandling &amp; MATH_ERRNO\n\t? errno == ERANGE\n\t: fetestexcept(FE_OVERFLOW | FE_UNDERFLOW);\n</span></code></pre>\n<p>note that this still doesn't guarantee that underflow is detected, since reporting underflow is entirely optional for the implementation.</p>\n<p>the reason you've never done this ever (and the reason the man pages don't mention this) is that posix specifies the functions differently:</p>\n<blockquote>\n<p>If the correct value is outside the range of representable values, ±HUGE_VAL, ±HUGE_VALF, or ±HUGE_VALL shall be returned (according to the sign of the value), and <code>errno</code> shall be set to <code>[ERANGE]</code>.</p>\n<p>If the correct value would cause an underflow, a value whose magnitude is no greater than the smallest normalized positive number in the return type shall be returned and <code>errno</code> set to <code>[ERANGE]</code>.</p>\n</blockquote>\n<p>so posix doesn't give a shit about <code>math_errhandling</code>; it always requires the implementation to set <code>errno</code> if overflow or underflow occurs. while it's not uncommon for posix to specify stricter requirements on functions than standard c, the fact that the man page never makes any note of this being an extension (neither <code>strtod(3)</code> nor the posix specification <code>strtod(3p)</code>) is really notable to me.</p>\n<p>whether or not posix's behavior is even compatible with standard c is... unclear. at least for <code>math.h</code> functions, setting <code>errno</code> regardless of the value of <code>math_errhandling</code> is permitted:</p>\n<p>7.12.2p8:</p>\n<blockquote>\n<p>If a domain, pole, or range error occurs and the integer expression <code>math_errhandling &amp; MATH_ERRNO</code> is zero, then <code>errno</code> shall either be set to the value corresponding to the error or left unmodified.</p>\n</blockquote>\n<p>but earlier on, when specifying <code>errno.h</code>, the standard says this:</p>\n<p>7.5p3:</p>\n<blockquote>\n<p>[...] The value of <code>errno</code> may be set to nonzero by a library function call whether or not there is an error, provided the use of <code>errno</code> is not documented in the description of the function in this document.</p>\n</blockquote>\n<p><code>errno</code> <em>is documented</em> in the description for these functions, and that description makes no mention of setting <code>errno</code> when <code>math_errhandling &amp; MATH_ERRNO</code> is zero. so that suggests that posix's behavior is non-conformant.</p>\n<p>but hang on! everything i've talked about so far is only for overflow and underflow. but if the string is malformed and can't be parsed as a number, then the standard doesn't specify any error at all:</p>\n<p>7.25.2.6p11:</p>\n<blockquote>\n<p>The functions return the converted value, if any. If no conversion could be performed, positive or unsigned zero is returned.</p>\n</blockquote>\n<p>instead, you're supposed to use the <code>endptr</code> parameter, and check afterward if <code>endptr == nptr</code> (i.e. the end pointer is the same as the start pointer, so no data was parsed):</p>\n<p>7.25.2.6p8:</p>\n<blockquote>\n<p>If the subject sequence is empty or does not have the expected form, no conversion is performed; the value of <code>nptr</code> is stored in the object pointed to by <code>endptr</code>, provided that <code>endptr</code> is not a null pointer.</p>\n</blockquote>\n<p>the man page <code>strtod(3)</code> says something similar:</p>\n<blockquote>\n<p>If no conversion is performed, zero is returned and (unless <code>endptr</code> is null) the value of <code>nptr</code> is stored in the location referenced by <code>endptr</code>.</p>\n</blockquote>\n<p>but check out what posix says:</p>\n<blockquote>\n<p>Upon successful completion, these functions shall return the converted value. If no conversion could be performed, 0 shall be returned, and <code>errno</code> may be set to <code>[EINVAL]</code>.</p>\n</blockquote>\n<p>the word &quot;may&quot; basically means that it's implementation-defined. but this is a big deal, because it's pretty common to check for errors by doing something like this:</p>\n<pre><code><span class=\"code-snippet\">errno = 0;\ndouble x = strtod(s, nullptr);\nif (errno != 0) {\n\t// ...\n}\n</span></code></pre>\n<p><code>strtod(3)</code> suggests doing exactly this:</p>\n<blockquote>\n<p>Since 0 can be legitimately returned on both success and failure, the calling program should set <code>errno</code> to 0 before the call, and then determine if an error occurred by checking whether <code>errno</code> has a nonzero value after the call.</p>\n</blockquote>\n<p>but even for posix-compatible libcs, this isn't portable! different conforming libcs may behave differently if no conversion can be performed. in fact...</p>\n<pre><code><span class=\"code-snippet\">errno = 0;\nstrtod(&quot;x&quot;, nullptr);\nprintf(&quot;%d\\n&quot;, errno);\n</span></code></pre>\n<p>on glibc, this prints 0, because glibc's <code>strtod</code> never sets <code>errno</code> to <code>EINVAL</code>. musl, on the other hand, <em>does</em> set <code>errno</code> to <code>EINVAL</code>, so this prints &quot;22&quot;. <strong>this is completely undocumented on the linux man page</strong>.</p>\n<p>it's also, from my reading of the standard, not conformant to standard c, because it's setting <code>errno</code> to a nonzero value in a function with other documented error conditions (and as far as standard c is concerned, invalid input isn't an error condition). musl <em>could</em> defend itself by saying that, because it doesn't set <code>errno</code> in its <code>math.h</code> functions, the <code>errno</code> condition in <code>strtod</code>'s description no longer applies, therefore there's no documented use for <code>errno</code> (since the use of <code>errno</code> is dependent on the value of <code>math_errhandling</code>). but that's clearly a stretch.</p>\n<p>either way, it's clear to me that the standard needs clearer wording here.</p>\n<h2>conclusion</h2>\n<p>just for fun, i figured i'd conclude with a list of all the &quot;correct&quot; ways to check for errors in the string to float conversion functions, just to hammer the point home:</p>\n<h3>overflow</h3>\n<ul>\n<li>\n<p>if you're targeting posix, set <code>errno</code> to 0 before the call, and afterward check <code>copysign(result, 1.0) == HUGE_VAL &amp;&amp; errno == ERANGE</code>.</p>\n</li>\n<li>\n<p>otherwise, set <code>errno</code> to 0 <em>and</em> call <code>feclearexcept(FE_OVERFLOW)</code> before the call, and, if <code>copysign(result, 1.0) == HUGE_VAL</code>, either check <code>errno == ERANGE</code> or <code>fetestexcept(FE_OVERFLOW)</code> after the call, depending on the value of <code>math_errhandling</code>.</p>\n<p>if you're targeting just one implementation, and you know which error-reporting methods it supports beforehand, you can skip the <code>math_errhandling</code> check and only support one of the two methods.</p>\n<p>if you're using <code>feclearexcept</code>/<code>fetestexcept</code>, make sure that the compiler knows you may be accessing the floating point environment: on gcc the relevant flag is <code>-ftrapping-math</code>, which is the default (unless you're using <code>-ffast-math</code>). there's also a standard pragma for this purpose: <code>#pragma STDC FENV_ACCESS ON</code>. this pragma isn't supported by gcc though.</p>\n</li>\n</ul>\n<h3>underflow</h3>\n<ul>\n<li>\n<p>if you're targeting posix, set <code>errno</code> to 0 before the call, and afterward check <code>result == 0.0 &amp;&amp; errno == ERANGE</code>.</p>\n<p>be sure to check specifically that <code>errno</code> is <code>ERANGE</code>, not just that it's nonzero. otherwise you'll end up with nonportable behavior.</p>\n</li>\n<li>\n<p>otherwise, if you're just targeting one implementation, check if it documents its behavior on underflow in <code>math.h</code> functions. the behavior is implementation-defined, so technically it's required to document it. but in practice, even clang doesn't bother documenting its implementation-defined shit, so don't hold your breath.</p>\n<p>but if it is documented, and it reports underflow errors, then, depending on the implementation's value of <code>math_errhandling</code>, either set <code>errno</code> to 0 before the call and check <code>result == 0.0 &amp;&amp; errno == ERANGE</code> after the call, or call <code>feclearexcept(FE_UNDERFLOW)</code> before the call and check <code>fetestexcept(FE_UNDERFLOW)</code> after the call.</p>\n</li>\n<li>\n<p>otherwise you're SOL.</p>\n<p>if you <em>reeally</em> need to check for underflow, and you <em>need</em> to use the libc function for some reason, here's the only option i can think of: check if <code>result == 0.0</code>, and if so, check yourself if the input string contains any nonzero digits before the exponent. if so, underflow occurred. this is difficult to get right though; read the description of <code>strtod</code> et al from the standard and make sure you cover all edge-cases.</p>\n</li>\n</ul>\n<h3>invalid input (no conversion)</h3>\n<ul>\n<li>pass in <code>&amp;endptr</code> as a second argument to the function, and then check if <code>endptr == nptr</code>. <code>errno</code> can't be relied on.</li>\n</ul>\n",
      "date_modified": "2026-10-10T05:37:18+00:00",
      "date_published": "2026-10-10T05:37:18+00:00",
      "external_url": "https://sebsite.pw/w/20261009-strtod.html",
      "id": "urn:aggr:item:c78d940b0932c9345eb7771586abb8d2aa7752f8",
      "summary": "Comments",
      "tags": [
        "news",
        "c"
      ],
      "title": "oh, apparently it's not possible to portably check for string-to-float conversion errors in standard c",
      "url": "https://aggr.aymericbeaumet.com/items/lobste-rs/2026-10-10-oh-apparently-it-s-not-possible-to-portably-check-for/"
    }
  ],
  "language": "en",
  "title": "sebsite.pw",
  "version": "https://jsonfeed.org/version/1.1"
}