Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does the ISO 9899 standard has reserved any use of the _t suffix for identifiers?

Tags:

c

I can read in many books and an other SO questions that the standard may expand the set of identifiers such as size_t or int32_t, so it reserves any use of the _t suffix for identifiers.

Is that true?

I could not find anything that discourage the use of this suffix in the ISO9899:1999 standard, but that standard is hard to read :(

like image 922
nowox Avatar asked Nov 28 '22 05:11

nowox


2 Answers

No, it's not true.

The standard reserves the right to add identifiers starting with int or uint and ending _t to the stdint.h header (§7.31.10). Those identifiers are technically only reserved if that header is included but since it almost always is, they should be treated as reserved.

In general, the standard reserves identifiers defined in standard headers, or mentioned in the future directions for standard headers (§7.31). Identifiers having external linkage (library functions) are reserved for that use (which doesn't stop you from using them as local or static variables, for example). If the library header is included, then its identifiers are reserved for use at file scope. Read §7.1.3 for details.

As that section indicates, the only identifiers unconditionally reserved are those which start with an underscore followed by a capital letter or a second underscore.

While reading the standard, it's important to understand the difference between contexts in which a name is reserved:

  • Reserved for any use (identifiers starting with an underscore followed by another underscore or a capital letter): these identifiers may be used by the implementation as macros or special symbols which are handled in some idiosyncratic way by the compiler. Do not ever define one of these in your code, and use the ones which are documented only as indicated by the documentation. Do not use such a symbol if it is not documented, even if you see it used in some standard library header. Or someone else's code.

  • Reserved at file scope (other identifiers starting with an underscore, not part of any standard header): These identifiers will not be used as macros, and you must not define them as macros either. You may use them as local variables, labels, parameters, and struct or union members. Personally, I wouldn't do this, but it's permitted. I prefer to put an underscore at the end of an identifier which is used in some internal context.

  • Reserved at file scope and as a macro name (any identifier mentioned in an included standard header, including in the future directions clause): Again, since these identifiers may be macros, you should treat them as off limits if you #include the associated header. The standard does allow you to #undef an identifier used as a function name in the standard library, although you might find that performance suffers because the macro wraps a construct with equivalent semantics but optimised performance.

  • Reserved for use as an identifier with external linkage (any identifier defined in any standard library header as having external linkage, whether or not the header is included, including the identifier errno): The weakest reservation. If you don't include the associated header, you're free to use such an identifier, even at file scope, as long as it is not externally visible. So it could be a file-scope static or an enumeration member or the tag of a struct or union. The point of this clause is not to allow you to deliberately shadow the name of a standard library function. Rather, it is to protect you from future additions to the standard library which might export an external symbol you're currently using. Of course, if your current use is as an externally visible identifier, you're still going to have a future problem. But on the whole, externally visible symbols should be prefixed with a package name to avoid name collisions with other libraries.


Having said all that, it's unwise to use an identifier that looks like it might be a standard identifier. Posix includes a list of over a hundred patterns for identifier names that it might use in the future, including all identifiers ending _t, so if you expect your code to be used in a Posix environment, you'll want to avoid those names. And while future C standard revisions might avoid adding new type names to existing headers (aside from the integer typenames mentioned above), you don't really want to preclude using any such new types, since they may well be useful. (And, according to a comment by @JensGustedt, who knows a lot more about the workings of the C working group than I do, there will be a couple of new type names in existing headers in C2x.)

like image 112
rici Avatar answered Dec 15 '22 05:12

rici


The _t suffix is not reserved by ISO 9899 as such. The future library directions for C11 revision does only say that (C11 7.31.10):

  1. Typedef names beginning with int or uint and ending with _t may be added to the types defined in the <stdint.h> header. [...]

That said, there are great many types with _t suffix defined in C11:

char16_t, char32_t, clock_t, cnd_t, constraint_handler_t, div_t, double_t, errno_t, fenv_t, fexcept_t, float_t, fpos_t, imaxdiv_t, int_fastN_t, int_leastN_t, intmax_t, intN_t, intptr_t, ldiv_t, lldiv_t, max_align_t, mbstate_t, mtx_t, ptrdiff_t, rsize_t, sig_atomic_t, size_t, thrd_start_t, thrd_t, time_t, tss_dtor_t, tss_t, uint_fastN_t, uint_leastN_t, uintmax_t, uintN_t, uintptr_t, wchar_t, wctrans_t, wctype_t, wint_t

POSIX, on the other hand, reserves the _t suffix for system use. The POSIX 1003.1 rationale has this excerpt:

To allow implementors to provide their own types, all conforming applications are required to avoid symbols ending in _t, which permits the implementor to provide additional types.

All in all, considering that the chances are that you want to use your C code in a POSIX system now or later, to steer away from using _t for your own types.