As a concrete example, the linked-to "who" uses:
if (entry.ut_type != USER_PROCESS)
continue;
The GNU one uses: if (IS_USER_PROCESS (utmp_buf))
The IS_USER_PROCESS() macro is in gnulib's readutmp.h (which would need to be included in the overall line cound): # define IS_USER_PROCESS(U) \
(UT_USER (U)[0] \
&& (UT_TYPE_USER_PROCESS (U) \
|| (UT_TYPE_NOT_DEFINED && UT_TIME_MEMBER (U) != 0)))
The UT_USER maps to ut_user on some systems, and ut_name on others: /* Accessor macro for the member named ut_user or ut_name. */
# if HAVE_UTMPX_H
# if HAVE_STRUCT_UTMPX_UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_user)
# endif
# if HAVE_STRUCT_UTMPX_UT_NAME
# undef UT_USER
# define UT_USER(Utmp) ((Utmp)->ut_name)
# endif
This is because, as
https://www.gnu.org/software/libc/manual/html_node/Logging-I... points out, "Note that the ut_user member of struct utmp is called ut_name in BSD. Therefore, ut_name is defined as an alias for ut_user in utmp.h"Each of those other macros supports cases where the machine supports a given test, and when it doesn't. Including for machines which don't implement ut_type! (That's what the UT_TYPE_NOT_DEFINED case is for, which falls back to using the time field ... which has its own set of variants!)
Portability is neither options nor cleverness, so I added it to the list of considerations. But then again, most people now don't need to support decades of history and scores of Unix variants.