[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Counterexamples in C programming and library documentation (was: [PA

From: Alejandro Colomar
Subject: Re: Counterexamples in C programming and library documentation (was: [PATCH v3] NULL.3const: Add documentation for NULL)
Date: Wed, 3 Aug 2022 01:54:18 +0200
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.1.0

Hi Branden,

On 8/2/22 21:06, G. Branden Robinson wrote:
[content warning: yet another long software engineering rant]

[this one took me many hours to read completely, including links, but was funny]

At 2022-08-02T13:38:22+0200, Alejandro Colomar wrote:
On 7/27/22 15:23, Douglas McIlroy wrote:

Incidentally, I personally don't use NULL. Why, when C provides a
crisp notation, 0, should one want to haul in an extra include file
to activate a shouty version of it?

While I don't endorse the shoutiness of the name selected for the macro
(and also don't endorse the use of a macro over making the null pointer
constant a bona fide language feature as was done in Pascal[1]), as
stronger typing has percolated into the C language--slowly, and against
great resistance from those who defend its original character as a
portable assembly language--distinctions have emerged between ordinal
types, reference types (pointers), and Booleans.

I'd like NULL being part of the language, as I'd like bool.

_Bool was necessary when it was introduced, to avoid collision with many handmade booleans, but reallistically, we're a few decades after C99, and it's hard to find redefinitions of bool in current code. And the few code bases that redefine it because they were written before I was even born, I don't think anyone is going to compile them with a hypothetical -std=c3x; and if they do, bool is the very least of the serious problems they'll find.

However, there's not much difference between the Standard C library and the language. Both are defined by the same ISO document, and both have the same status of mandatory for an implementation (except for a few optional libc features). You are required by the Standard to treat libc macros and other identifiers as if they were language keywords, in the sense that you are not allowed to #undef them or hide functions with a macro, etc.

And the reason for that is that the Standard recognizes that compilers might decide to ignore the Standard, and go further and define a bona fide language keyword, like GNU cc and libc do with NULL and bool:

$ grepc -ktm bool /usr/include
/usr/include/curses.h:288:#define bool NCURSES_BOOL
/usr/include/ruby-3.0.0/ruby/internal/stdbool.h:45:# define bool  _Bool
/usr/include/x86_64-linux-gnu/ruby-3.0.0/rb_mjit_min_header-3.0.4.h:21075:#define bool _Bool

$ grepc -ktm NULL /usr/include | grep -v ruby
/usr/include/php/20210902/ext/mbstring/libmbfl/mbfl/mbfl_defs.h:36:#define NULL (0L) /usr/include/php/20210902/ext/mbstring/libmbfl/mbfl/mbfl_defs.h:38:#define NULL (void *)(0L)
/usr/include/tirpc/rpc/types.h:54:#     define NULL     0
/usr/include/unicode/utypes.h:186:#define NULL    nullptr
/usr/include/unicode/utypes.h:188:#define NULL    ((void *)0)

So, in practice, it's a language feature in GNU C. Not in ISO C, but who cares? Today, GCC and Clang cover 99 % (and that's likely an understatement) of the C implementations I care about.

I feel this is unequivocally a good thing.

Yes, people will say that a zero (false) value in all of these types has
exactly the same machine representation, even when it's not true[2], so
a zero literal somehow "tells you more".

But let me point out two C programming practices I avoid and advocate
against, and explain why writing code that way tell us less than many of
us suspect.

(1) Setting Booleans like this.


Not only this is unreadable.  This is dangerous.

If the variable is declared as _Bool, then the compiler should emit the same code as for 'nflag = 1'. If it doesn't, it is unconforming to ISO C. See Arithmetic operands::Boolean type:

When any scalar value is converted to _Bool, the result is 0 if the value compares equal to 0; otherwise, the result is 1.

(Of course, if the compiler can guarantee that no-one will read the value as an integer, or that it won't overflow, it is allowed to produce non-conforming code.)

If the variable is declared as an integer type, it's likely that someone will slightly change the code without realizing a tiny detail, and the ++ will result in an overflow/wrap around.

     But I'm not done.  The above exhibit abuses the incrementation
     operator.  Firstly this makes your data type conceptually murky.
     What if `nflag` (or whatever you called it) was already `1`?  Now
     it's `2`.  Does this matter?  Are you sure?  Have you checked every
     path through your code?  (Does your programming language help you to
     do this?  Not if it's C.  <bitter laugh>)  Is a Boolean `2`
     _meaningful_, without programming language semantics piled on to
     coerce it?  No.  Nobody answers "true or false" questions in any
     other domain of human experience with "2".  Nor, really, with "0" or
     "1", except junior programmers who think they're being witty.  This
     is why the addition of a standard Boolean type to C99 was an
     unalloyed good.

And 2 would still be not so bad. Consider if it is n, for an unbounded n. bool can't overflow or wrap around; other integers can.

     In my own experience the best optimizations I've done are those
     which dropped code that wasn't doing anything useful at all.
     Eliminating _unnecessary_ work is _never_ a "premature"
     optimization.  It removes sites for bugs to lurk and gives your
     colleagues less code to read.  (...says the guy who thinks nothing
     of dropping a 20-page email treatise on them at regular intervals.)

Heh :)

     And another thing!

It was funny to read this and check that I still had more than half email below.

I submit that using `0`
     as a null pointer constant, whether explicitly or behind the veil of
     a preprocessor macro, hides _necessary_ information from the

     For me personally, this fact alone is enough to justify a
     within-language null pointer constant.

ISO C defines NULL as a black-box macro. They call it macro, but it has all the same requirements that a keyword like int has: You can't #undef any of them, nor redefine them in any way. I don't understand what do you miss so much from a keyword that NULL doesn't have. The only real difference is that the ISO document uses the word macro instead of keyword.


     I don't think it is an accident that there are no function pointer
     literals in the language either (you can of course construct one
     through casting, a delightfully evil bit of business).

Could you show an example?  I'm curious.

 The lack
     made it easier to paper over the deficiency.  Remember that C came
     out of the Labs without fully-fledged struct literals ("compound
     literals"), either.  If I'd been at the CSRC--who among us hasn't
     had that fantasy?--I'd have climbed the walls over this lack of

As I've said several times, K&R C was excellent for their time, but very deficient compared to the latest ISO C. I wouldn't blame them (nor the programmers that have abused it). C++ was bad when released, and is even worse some decades after. K&R (and the [ab]users of their language) have the merit of having developed a language that could be polished to the beautiful language we have today.

I will grant that the inertia against the above two points was, and
remains, strong.  C++, never a language to reject a feature[6], resisted
the simple semantics and obvious virtues of a Boolean data type for
nearly the first 20 years of its existence, and only acquired `nullptr`
in C++11.  Prior to that point, C++ was militant about `0` being the
null pointer constant, in line with Doug's preference--none of this
shouty "NULL" nonsense.

And I don't understand why C++ added nullptr. NULL was already in use for where programmers are now expected to write nullptr. C++ could have just said: from now on, NULL is a language keyword that creates a null pointer. You don't need to include a header to get it anymore.

Programs would have just started using it without even noticing it, with the added safety of using a keyword.

And they didn't seem too shy when making bool be a keyword, nor when they gave a completely new meaning to auto. Backwards compatibility with old code defining stuff or with C are clearly not a problem, when bool and auto could be made keywords.

Because I don't know what foo(a, b, 0, 0) is, and I don't know from
memory the position of all parameters to the functions I use (and
checking them every time would be cumbersome, although I normally do,
just because it's easier to just check, but I don't feel forced to do
it so it's nicer).

Kids these days will tell you to use an IDE that pops up a tool tip with
the declaration of 'foo'.  That this is necessary or even as useful as
it is discloses problems with API design, in my opinion.

Boy, don't remind me of that. I still remember certain "senior" programmer recommending me to use an IDE to "understand" his incomprehensible code. And the worse thing is I'm not talking about a kid. (Actually, I'm the Millenial.)

Was the third parameter to foo() the pointer and the fourth a length,
or was it the other way around?  bcopy(3) vs memcpy(3) come to mind,
although of course no-one would memcpy(dest, NULL, 0) with hardcoded
0s in their Right Mind (tm) (although another story is to call
memcpy(dest, src, len) with src and len both 0).

The casual inconsistency of the standard C library has many more
manifestations than that.

Knowing with 100% certainty that something is a pointer or an integer
just by reading the code and not having to go to the definition
somewhere far from it, improves readability.

I entirely agree.

Even with a program[...] that finds the definitions in a big tree of
code, it would be nice if one wouldn't need to do it so often.

Or like Atom[7], which has been a big hit among Millennial programmers.

I haven't used Atom, but it seems like an IDE, isn't it?  If so, no thanks.

grepc(1) is a sh(1) script that I wrote around pcregrep(1) and basic Unix commands. It's not another plugin for an editor; it's a Unix-friendly command.

It is a one-shot program with no configuration nor interactivity. It's quite fast, and can search in any unknown code base (including a whole OS file tree).

See an example of typical use (and actually a real use case that I needed a few weeks ago[1]):

$ time grepc SYS_pivot_root / 2>/dev/null
# define SYS_pivot_root __NR_pivot_root

real    0m8.204s
user    0m7.510s
sys     0m1.954s

I included the time to run it to show that it can find anything in the OS really fast (see a larger example at the end of this email[2]). You may want to give it a try. It even comes with a manual page! And it uses .MR (in a way that you won't miss the text if you lose it)!

[1]: <>

Too bad, thanks to who acquired GitHub, it's being killed off and
replaced by Visual Studio now.  We call this market efficiency.

Kind of the argument that some use to object to my separation of
man3type pages, but for C code.

Here I disagree,

I was more referring to Ingo's comments, who said repeatedly that types should be documented in the function pages, because one shouldn't need to open a separate page to search for the type definition when reading about a function. I admit it's still not a perfect match with my argument of not wanting to look at the definition of foo() to know if a 0 is an int or a pointer, but kind of, I thought when I wrote it.

because while we are clearly aligned on the null
pointer, point,

And I think Ingo also agrees.

I will continue to defend the position that
a man page for a header file--where an API has been designed rather than
accreted--is a preferable place to document the data types and constants
it defines, as well as either an overview or a detailed presentation of
its functions, depending on its size and/or complexity.

And in this context, I also agree with you. If I were creating my own library, I'd write exactly one manual page for every header file. And if a header file's manual page is too big, it's because I should split the header file.

In fact, something like 4 years ago, much before I ever learned how manual pages were written (that Debian has compressed manual pages didn't help), I attempted to write (in .rst files) manual pages for my own library, and I decided to write one for each header. Each header in that library usually contains between 1 and 10 functions, depending on complexity. And there are just a dozen or so types in the library, so they could be described in the manual page for the header that defines them.

But of course, if I were to define my own library, each symbol would be provided only in one header (and of course, any other header would be allowed to provide such a symbol by inclusion, in an undocumented way)

But libc is a mess, with many headers redefining stuff, many others not being allowed to provide a given symbol, and similar weird rules.

I think the overwhelming importance of the C library to your documentary
mission in the Linux man-pages project is obscuring the potential of
elegant man pages for _other_ libraries.  What passes for the C standard
library on _any_ system is quite a crumbcake.

Yeah, mtk was more focused on documenting the syscalls (his job is all about the kernel). I've allways been more of a libc user, and only used syscalls in few cases in the past (now more often, but still I find myself using library calls much more often than kernel interfaces). That inevitably results in that I end up documenting much of the libc stuff that had never been documented before.

The fact that you can't cram the C library into the shape I espouse
without making the pages huge and unwieldy is the fault of the library,

It certainly is.

I humbly(!) suggest, not the fault of the principle.

We agree.

 But I'd be a long
way from the first person to note that the C library is schizophrenic
upon even cursory inspection.

Still, I hope that in the long term the language can be fixed, and we don't need to go so far as to invent a new language, say C+=2.

Is it true that Plauger never wrote another book after his (dense but
incredibly illuminating, A+++, would read again) _The Standard C
Library_?  Did writing his own libc and an exposition of it "break" him
in some way?  I imagine that he got perhaps as good a look as anyone's
ever had at how much better a standard library C could have had, if only
attention had been paid at the right historical moments.  He saw how
entrenched the status quo was, and decided to go sailing...forever.
Just an irresponsible guess.

I would like to find a good place to state the recommendation that
documentors of _other_ libraries should not copy this approach of
trifurcating presentations of constants, data types, and functions.
In a well-designed API, these things will be clearly related,
mechanically coupled, and should be considered together.

As you hinted, you shouldn't aim documentors, but designers.
If the design is good, it will ask for a header-file documentation model, I think.

What do you think?

As always, spirited contention of any of my claims is welcome.


[1] I say that, but I don't see it in the 1973 "Revised Report" on the
     language.  I guess "nil" came in later.  Another Algol descendant,
     Ada 83, had "null".  And boy am I spoiling to fight with someone
     over the awesomeness of Ada, the most unfairly maligned of any
     language known to me.

I admit I've never seen Ada, but I've used VHDL, which is heavily based on Ada (AFAIK). I hate it, sorry. It's unnecessarily verbose. To begin with, who needs 'begin' and 'end' when '{' and '}' can do?

[3] Pop quiz: what assembly language did Branden grow up on?  It's hard
     to escape our roots in some ways.

I'm too young to know this one :)

[4] I won't go so far as to say speculative execution is _stupid_,
     though I wonder if it can ever actually be implemented without
     introducing side channels for attack.  Spec ex is performed, as I
     understand it, because Moore's Law is dead, and CPU manufacturers
     are desperately trying to satisfy sales engineers and certain
     high-volume customers who are only willing to pay for cores that the
     premium prices (profit margins) that the industry has been
     accustomed to for 50 years.  Purchasing decisions are made by suits,
     and suits like to get to the bottom line, like "number go up".
[6] Stroustrup would disagree and can support his argument; see his
     writings on the history of the language.

I think


$ time grepc -ktm ARRAY_SIZE / 2>/dev/null
/home/alx/src/alx/libalx/include/alx/base/compiler/size.h:40:#define ARRAY_SIZE(arr) (__arraycount((arr)) + alx_must_be_array(arr)) /home/alx/src/bsd/freebsd/freebsd-src/contrib/libevent/test/regress_dns.c:75:#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h:351:#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/llvm-project/compiler-rt/lib/scudo/standalone/internal_defs.h:20:#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/ntp/sntp/libevent/test/regress_dns.c:1675:#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/ofed/opensm/opensm/osm_torus.c:64:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/wpa/src/utils/common.h:556:#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /home/alx/src/bsd/freebsd/freebsd-src/contrib/xz/src/common/sysdefs.h:189:# define ARRAY_SIZE(array) (sizeof(array) / sizeof((array)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/arm/ti/omap4/omap4_prcm_clks.c:446:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/compat/linuxkpi/common/include/linux/kernel.h:302:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/contrib/edk2/Include/Base.h:1312:#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/contrib/ncsw/inc/ncsw_ext.h:170:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccompile.h:124:#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/contrib/openzfs/include/os/freebsd/spl/sys/sysmacros.h:69:#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/contrib/openzfs/lib/libspl/include/os/linux/sys/sysmacros.h:43:#define ARRAY_SIZE(a) (sizeof (a) / sizeof (a[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/axgbe/xgbe_osdep.h:197:#define ARRAY_SIZE(x) nitems(x) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/bxe/bxe.h:121:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/bxe/bxe_elink.h:107:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/cxgb/cxgb_osdep.h:195:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/cxgbe/cudbg/cudbg_entity.h:106:#define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/cxgbe/osdep.h:94:#define ARRAY_SIZE(x) nitems(x) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/drm2/drm_os_freebsd.h:109:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/ice/ice_osdep.h:197:#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/isci/scil/sci_util.h:64:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/ixl/i40e_osdep.h:95:#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/ocs_fc/ocs_os.h:90:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/qlnx/qlnxe/bcm_osal.h:140:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/smartpqi/smartpqi_defines.h:643:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/freebsd/freebsd-src/usr.sbin/bhyve/hda_codec.c:135:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/bsd/openbsd/src/gnu/gcc/include/libiberty.h:582:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/lib/libiberty/include/libiberty.h:459:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/llvm/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h:334:#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/llvm/compiler-rt/lib/scudo/standalone/internal_defs.h:20:#define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0])) /home/alx/src/bsd/openbsd/src/gnu/usr.bin/binutils-2.17/bfd/elf32-ppc.c:4965:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/usr.bin/binutils-2.17/include/libiberty.h:592:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/usr.bin/binutils/bfd/elf32-ppc.c:1600:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/gnu/usr.bin/binutils/include/libiberty.h:299:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/bsd/openbsd/src/sys/dev/pci/sv.c:125:#define ARRAY_SIZE(foo) ((sizeof(foo)) / sizeof(foo[0])) /home/alx/src/gnu/glibc/math/gen-auto-libm-tests.c:164:#define ARRAY_SIZE(A) (sizeof (A) / sizeof ((A)[0])) /home/alx/src/gnu/gnulib/lib/nproc.c:62:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/gnu/gnulib/lib/physmem.c:92:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/gnu/gnupg/tpm2d/intel-tss.h:208:#define ARRAY_SIZE(A) (sizeof(A)/sizeof(A[0])) /home/alx/src/gnu/groff/gnulib/lib/nproc.c:62:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/gnu/groff/gnulib/lib/physmem.c:92:#define ARRAY_SIZE(a) (sizeof (a) / sizeof ((a)[0])) /home/alx/src/illumos/illumos-gate/usr/src/cmd/bhyve/hda_codec.c:135:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/cmd/mdb/common/modules/stmf_sbd/stmf_sbd.c:41:#define ARRAY_SIZE(a) (sizeof (a) / sizeof (*a)) /home/alx/src/illumos/illumos-gate/usr/src/cmd/stat/common/acquire.c:36:#defineARRAY_SIZE(a) (sizeof (a) / sizeof (*a)) /home/alx/src/illumos/illumos-gate/usr/src/grub/grub-0.97/netboot/r8169.c:76:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/tools/ctf/common/ctf_headers.h:81:#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) /home/alx/src/illumos/illumos-gate/usr/src/tools/smatch/src/lib.h:43:#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/tools/smatch/src/validation/sm_array_overflow2.c:3:#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/tools/smatch/src/validation/sm_array_overflow3.c:3:#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/tools/smatch/src/validation/sm_array_overflow4.c:4:#define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/arn/arn_core.h:50:#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/bnxe/577xx/drivers/common/lm/device/lm_pf.c:559:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/bnxe/577xx/hsi/hw/include/clc.h:86:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/cxgbe/t4nex/cudbg_entity.h:126:#define ARRAY_SIZE(_a) (sizeof((_a)) / sizeof((_a)[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/cxgbe/t4nex/osdep.h:146:#define ARRAY_SIZE(x) (sizeof (x) / sizeof ((x)[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/io/qede/579xx/drivers/ecore/bcm_osal.h:561:#define ARRAY_SIZE(_arr) (sizeof(_arr) / sizeof((_arr)[0])) /home/alx/src/illumos/illumos-gate/usr/src/uts/common/sys/sysmacros.h:377:#define ARRAY_SIZE(x) (sizeof (x) / sizeof (x[0])) /home/alx/src/linux/linux/arch/mips/boot/tools/relocs.h:32:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/arch/powerpc/boot/types.h:7:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/arch/um/include/shared/user.h:17:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/arch/x86/boot/boot.h:31:#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) /home/alx/src/linux/linux/arch/x86/tools/relocs.h:23:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/fs/orangefs/orangefs-debug.h:21:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/fs/unicode/mkutf8data.c:63:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/include/linux/kernel.h:55:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) /home/alx/src/linux/linux/samples/bpf/cookie_uid_helper_example.c:34:#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) /home/alx/src/linux/linux/samples/bpf/xdp_sample.bpf.h:139:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/samples/bpf/xsk_fwd.c:33:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/samples/seccomp/user-trap.c:24:#define ARRAY_SIZE(x) (sizeof(x) / sizeof(*(x))) /home/alx/src/linux/linux/scripts/dtc/util.h:27:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/scripts/genksyms/genksyms.c:406:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/scripts/kallsyms.c:28:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) /home/alx/src/linux/linux/scripts/kconfig/preprocess.c:15:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/scripts/mod/file2alias.c:737:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/scripts/selinux/mdp/mdp.c:40:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/tools/arch/x86/kcpuid/kcpuid.c:10:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/gpio/gpio-utils.h:19:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/tools/iio/iio_utils.h:19:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) /home/alx/src/linux/linux/tools/include/linux/kernel.h:102:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) /home/alx/src/linux/linux/tools/lib/traceevent/plugins/plugin_futex.c:15:#define ARRAY_SIZE(_a) (sizeof(_a) / sizeof((_a)[0])) /home/alx/src/linux/linux/tools/lib/traceevent/plugins/plugin_xen.c:103:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/tools/power/cpupower/utils/cpupower.c:23:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/linux/linux/tools/spi/spidev_test.c:26:#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/bpf_util.h:31:# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/progs/netif_receive_skb.c:27:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/progs/ ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/progs/test_sysctl_loop1.c:13:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/progs/test_sysctl_loop2.c:13:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/testing/selftests/bpf/progs/test_sysctl_prog.c:19:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/linux/tools/testing/selftests/kselftest.h:53:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/tools/testing/selftests/kselftest_harness.h:683:#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) /home/alx/src/linux/linux/tools/usb/usbip/libsrc/usbip_device_driver.c:30:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/linux/tools/virtio/linux/kernel.h:52:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /home/alx/src/linux/linux/tools/vm/page-types.c:211:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /home/alx/src/linux/man-pages/man-pages/tmp/src/man2/seccomp.2.d/seccomp.c:13:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/man-pages/man-pages/tmp/src/man2/seccomp_unotify.2.d/seccomp_unotify.c:25:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/src/linux/man-pages/man-pages/tmp/src/man2/sysctl.2.d/sysctl.c:11:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/tmp/man-pages/tmp/src/man2/seccomp.2.d/seccomp.c:13:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/tmp/man-pages/tmp/src/man2/seccomp_unotify.2.d/seccomp_unotify.c:25:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /home/alx/tmp/man-pages/tmp/src/man2/sysctl.2.d/sysctl.c:11:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) /usr/include/compel/common/compiler.h:10:#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) /usr/include/xorg/wacom-util.h:26:#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) /usr/share/doc/git/contrib/credential/wincred/git-credential-wincred.c:12:#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) /usr/src/linux-headers-5.18.0-1-common/include/linux/kernel.h:55:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) /usr/src/linux-headers-5.18.0-2-common/include/linux/kernel.h:55:#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr)) /home/alx/src/bsd/freebsd/freebsd-src/sys/dev/wtap/plugins/visibility.h:41:#define ARRAY_SIZE (32) //We support a maximum of 1024 nodes for now /home/alx/src/bsd/openbsd/src/sys/dev/pci/drm/include/linux/kernel.h:43:#define ARRAY_SIZE nitems /home/alx/src/illumos/illumos-gate/usr/src/lib/libdwarf/common/gennames.c:87:#define ARRAY_SIZE 300

real    0m9.586s
user    0m9.117s
sys     0m2.061s

You can see that it found things in Linux, FreeBSD, OpenBSD, Illumos, glibc, ... and all in one run. I still don't know any real competition for this program :)

And for the more common case of searching for the definition of a symbol in a single code base, the times are almost instantaneous:

alx@asus5775:~/src/nginx/unit$ time grepc nxt_getpid
#define nxt_getpid() \

#define nxt_getpid() \

real    0m0.069s
user    0m0.090s
sys     0m0.020s



Alejandro Colomar

Attachment: OpenPGP_signature
Description: OpenPGP digital signature

reply via email to

[Prev in Thread] Current Thread [Next in Thread]