Skip to content

Conversation

@alejandro-colomar
Copy link
Collaborator

Cc: @uecker
Cc: @chrisbazley

This is an experiment about mimicking templates in C with macros. If we get rid of the trailing \, this looks quite nice.

@uecker
Copy link
Contributor

uecker commented Mar 10, 2025 via email

@alejandro-colomar
Copy link
Collaborator Author

alejandro-colomar commented Mar 10, 2025

Am Montag, dem 10.03.2025 um 09:39 -0700 schrieb Alejandro Colomar:
I would just write it as STRTON__ ## in the definition instead of using the STRTON macro, which would get rid fo the off-by-one. I also hides less of mechanism which I think is good.

The good thing about using STRTON() is that it looks like a function definition. grepc(1) (my regex-based program for grepping C code) finds it just fine. However, if I use ##, then the regex doesn't find it.

I also wonder whether you can replace the code in the c file with something such as extern inline typeof(STRTON__ ## uintmax_t) STRTON__ ## uintmax_t; instead of repeating all the arguments.

I'm not too worried, since that repetition is checked by the compiler. Also, the same argument applied: regex-based programs will find the prototypes using STRTON().

https://www.alejandro-colomar.es/src/alx/alx/grepc.git/tree/bin/grepc

@alejandro-colomar
Copy link
Collaborator Author

alejandro-colomar commented Mar 12, 2025

Am Montag, dem 10.03.2025 um 09:39 -0700 schrieb Alejandro Colomar:
I would just write it as STRTON__ ## in the definition instead of using the STRTON macro, which would get rid fo the off-by-one. I also hides less of mechanism which I think is good.

The good thing about using STRTON() is that it looks like a function definition. grepc(1) (my regex-based program for grepping C code) finds it just fine. However, if I use ##, then the regex doesn't find it.

I also wonder whether you can replace the code in the c file with something such as extern inline typeof(STRTON__ ## uintmax_t) STRTON__ ## uintmax_t; instead of repeating all the arguments.

I'm not too worried, since that repetition is checked by the compiler. Also, the same argument applied: regex-based programs will find the prototypes using STRTON().

https://www.alejandro-colomar.es/src/alx/alx/grepc.git/tree/bin/grepc

@uecker

Actually, I correct myself. grepc(1) is able to grep the template definition with ## in its name as long as you include that in the search term.

$ grepc -h CMP .
#define CMP(T)  cmp__ ## T  // For use as a callback
$ grepc -hC1 'cmp__ ## T' .
#def template_cmp(T)
inline int
cmp__ ## T(const void *key, const void *elt)
{
	const T  *k = key;
	const T  *e = elt;

	if (*k < *e)
		return -1;
	if (*k > *e)
		return +1;
	return 0;
}
#enddef

So, I'll follow your suggestion and make it explicit that I'm using ## in the template definition. It will make the machinery more readable.

@alejandro-colomar
Copy link
Collaborator Author

I also wonder whether you can replace the code in the c file with something such as extern inline typeof(STRTON__ ## uintmax_t) STRTON__ ## uintmax_t; instead of repeating all the arguments.

No, you can't.

search/cmp/cmp.c:12:28: error: stray '##' in program
   12 | extern inline typeof(CMP__ ## int)     CMP__ ## int;
      |                            ^~
search/cmp/cmp.c:12:22: error: 'CMP__' undeclared here (not in a function); did you mean 'CMP'?
   12 | extern inline typeof(CMP__ ## int)     CMP__ ## int;
      |                      ^~~~~
      |                      CMP
search/cmp/cmp.c:12:27: error: expected ')' before 'int'
   12 | extern inline typeof(CMP__ ## int)     CMP__ ## int;
      |                     ~     ^   ~~~
      |                           )

Concatenation doesn't work outside of macros. I guess I'll either concatenate myself, or write a small macro for that.

@alejandro-colomar alejandro-colomar force-pushed the template branch 3 times, most recently from 084f3d7 to e287e1b Compare March 13, 2025 02:04
extern inline void *lfind_(const void *k, const void *a, size_t n, size_t ksize,
typeof(int (const void *k, const void *elt)) *cmp);
extern inline const int *LFIND__int(size_t n;
const int *k, const int a[n], size_t n);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
extern inline const int *LFIND__int(size_t n;
const int *k, const int a[n], size_t n);
extern inline const long *LFIND__long(size_t n;
const long *k, const long a[n], size_t n);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
extern inline const long *LFIND__long(size_t n;
const long *k, const long a[n], size_t n);
extern inline const u_int *LFIND__u_int(size_t n;
const u_int *k, const u_int a[n], size_t n);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
extern inline const u_int *LFIND__u_int(size_t n;
const u_int *k, const u_int a[n], size_t n);
extern inline const u_long *LFIND__u_long(size_t n;
const u_long *k, const u_long a[n], size_t n);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
/* lfind(3) wants a pointer to n for historic reasons. */ \
return lfind(k, a, &n, sizeof(T), CMP(T)); \
}
template_LFIND(int);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
{ \
lsearch(k, a, n, sizeof(T), CMP(T)); \
}
template_LSEARCH(int);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
lsearch(k, a, n, sizeof(T), CMP(T)); \
}
template_LSEARCH(int);
template_LSEARCH(long);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
}
template_LSEARCH(int);
template_LSEARCH(long);
template_LSEARCH(u_int);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
template_LSEARCH(int);
template_LSEARCH(long);
template_LSEARCH(u_int);
template_LSEARCH(u_long);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'k'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
template_QSORT(int);
template_QSORT(long);
template_QSORT(u_int);
template_QSORT(u_long);

Check notice

Code scanning / CodeQL

Short global name

Poor global variable name 'a'. Prefer longer, descriptive names for globals (eg. kMyGlobalConstant, not foo).
@alejandro-colomar alejandro-colomar changed the title lib/atoi/strtoi/: STRTON(): Add template Use templates to replace macros Mar 13, 2025
@alejandro-colomar alejandro-colomar changed the title Use templates to replace macros Use templates to avoid repetition, and to add type safety Mar 13, 2025
@alejandro-colomar alejandro-colomar force-pushed the template branch 2 times, most recently from 12ff7c4 to 7716e5e Compare March 13, 2025 21:37
@alejandro-colomar alejandro-colomar force-pushed the template branch 5 times, most recently from 818eb20 to 40b10cf Compare June 2, 2025 09:32
@alejandro-colomar alejandro-colomar force-pushed the template branch 4 times, most recently from f101a61 to 25091f3 Compare June 7, 2025 18:11
@alejandro-colomar alejandro-colomar force-pushed the template branch 2 times, most recently from 0a3d6a1 to d32bec8 Compare July 20, 2025 14:36
@alejandro-colomar alejandro-colomar force-pushed the template branch 8 times, most recently from 97fe3e3 to 7f60d6d Compare October 23, 2025 17:41
This macro is useful to implement QChar versions of functions.
See ISO C23 for a description of what QChar is.

Signed-off-by: Alejandro Colomar <[email protected]>
It won't hurt; if the type is convertible, it will be accepted; and if
it's not convertible, the compiler will reject it at call site.
This 'default' branch allows converting a QChar** into a char**.

Signed-off-by: Alejandro Colomar <[email protected]>
This allows grepping for casts more easily.
It also reduces the damage of a bogus cast.

Signed-off-by: Alejandro Colomar <[email protected]>
This adds readability at call site, and simplifies the implementation.

Signed-off-by: Alejandro Colomar <[email protected]>
We don't need the return value of LSEARCH() at all, so let's remove it.
We don't need to modify the return value of LFIND(), so make it const.

Signed-off-by: Alejandro Colomar <[email protected]>
We can use _Generic() on the element type, without using a pointer type.

Signed-off-by: Alejandro Colomar <[email protected]>
@alejandro-colomar alejandro-colomar force-pushed the template branch 2 times, most recently from ecd4e78 to 8458aa1 Compare October 28, 2025 11:37
This allows us to get rid of ({}), which is a GNU extension.

Signed-off-by: Alejandro Colomar <[email protected]>
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.

2 participants