Skip to content

Conversation

@MisterDA
Copy link
Contributor

@MisterDA MisterDA commented Dec 11, 2025

Last year I rewrote the C code to use declarations in for loops init-clauses in #13289 (a C99 feature!). This year, I propose a fast-forward in time to introduce a new C2y operator, _Countof. This operator counts the number of elements in an array. If the operand is not an array, it produces a compilation error. This adds a bit of type safety and consistency.

int dracula[n];
_Countof(dracula);  // returns n elements, not n bytes

See also, for __has_feature and __has_extension:

The trend since C11 seems to introduce new operators as _Operator (as the _[A-Z] prefix is reserved by the standard for identifiers), introduce macros as #define operator _Operator in a new <std….h> header, and in a later revision turn the macro into a regular keyword and make the header a no-op. If we were to include the lowercase identifier in a public header, it could interact badly with other projects also defining it. Regarding the spelling, my preference goes to using countof over _Countof or CAMLcountof. I've tried to come up with a backward and forward compatible definition of countof, that I've kept private under CAML_INTERNALS.

This patch was generated using Coccinelle, with the semantic patch below. Only the #define CAML_INTERNALS were manually added, as needed.

@n@
identifier NSPEEDS,speedtable;
@@
- #define NSPEEDS (sizeof(speedtable) / sizeof(speedtable[0]))
@@
identifier n.NSPEEDS;
@@
- NSPEEDS
+ countof(speedtable)
@m@
identifier ARR_SIZE,E;
@@
- #define ARR_SIZE(a)    (sizeof(a) / sizeof(*(a)))
@@
expression E;
identifier m.ARR_SIZE;
@@
- ARR_SIZE(E)
+ countof(E)
@@
type T;
T[] E;
@@
- (sizeof(E)/sizeof(*E))
+ countof(E)
@@
type T;
T[] E;
@@
- (sizeof(E)/sizeof(E[...]))
+ countof(E)
@@
type T;
T[] E;
@@
- (sizeof(E)/sizeof(T))
+ countof(E)
@@
type T;
const T[] E;
@@
- (sizeof(E)/sizeof(T))
+ countof(E)

@MisterDA MisterDA force-pushed the c2y-countof branch 2 times, most recently from b347c3a to 00d0f00 Compare December 11, 2025 14:00
@dra27
Copy link
Member

dra27 commented Dec 11, 2025

Kudos for using Coccinelle to apply the change! I like your argument for the name of countof, but I'm slightly worried at the header - misc.h is pulled in by so many other headers, and saying "it's guarded by CAML_INTERNALS" feels a bit like the argument used in glibc 2.34 to justify changing SIGSTKSZ which led to #10266 (the rationale was that it only happened if GNU_SOURCE was defined IIRC), and I'm still a bit scarred by that.

Given that we only need it in the C sources, perhaps that can just go in a separate internal header? (misc_internal.h or something?!) - still guarded by CAML_INTERNALS, but just not risking being pulled in arbitrarily by other headers.

@MisterDA
Copy link
Contributor Author

Yes, a private header is the better alternative that I didn't dare to suggest, but has my preference too. I'll push a revision with a new header.

This operator counts the number of elements in an array.
If the operand is not an array, it produces a compilation error.

- [N3369 - New `_Lengthof()` operator (v4)][N3369] (later renamed to `_Countof`);
- [GCC Determining the Number of Elements of Arrays][GCC _Countof];
- [Clang C2y `_Countof`][Clang _Countof].

[Clang _Countof]: https://clang.llvm.org/docs/LanguageExtensions.html#c2y-countof
[GCC _Countof]: https://gcc.gnu.org/onlinedocs/gcc/_005fCountof.html
[N3369]: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3369.pdf

See also, for `__has_feature` and `__has_extension`:

- [Clang `__has_feature` and `__has_extension`][Clang];
- [GCC `__has_feature`][GCC1];
- [GCC `__has_extension`][GCC2].

[Clang]: https://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension
[GCC1]: https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005ffeature.html
[GCC2]: https://gcc.gnu.org/onlinedocs/cpp/_005f_005fhas_005fextension.html

Introduce a private `misc_internals.h` file and define `countof`
there.
This patch was generated using Coccinelle, with a semantic patch.
Occurrences that Coccinelle did not find.
@gadmm
Copy link
Contributor

gadmm commented Dec 15, 2025

I am missing what was wrong with 00d0f00 regarding CAML_INTERNALS, which is indeed meant to handle internal definitions (https://ocaml.org/manual/5.4/intfc.html#s:c-internal-guidelines). Users know they should not use it (unless they know what they do and are ready for their program to break in future OCaml versions). In contrast, _GNU_SOURCE is a documented glibc feature test macro to invoke GNU-specific extensions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants