Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Post History
A function is the obvious solution since it only comes with one evaluation per argument before the function is called. If the only rationale for using macros over functions is to avoid casts, then...
#2: Post edited
- If the only rationale for using macros over functions is to avoid casts, then just make the macro a wrapper macro for the function calls, similar to how a C standard lib will have to implement _QVoid_ and _QChar_ fictional types in C23.
- Assuming we do not allow implicit `void` pointer conversions (for the same reason as we don't allow casts - type safety), then:
- ```c
- #include <string.h>
- char* strnul (char* s)
- {
- return (s + strlen(s));
- }
- const char* strnulc (const char* s)
- {
- return (s + strlen(s));
- }
- #define strnul(s) \
- _Generic((s), \
- char*: strnul, \
- const char*: strnulc)(s)
- ```
- If `void` pointers should be allowed then simply add `void*: strnul` to `_Generic` (and one for `const void*` too). The implicit conversion to `char*` also means we can do standard-compliant pointer arithmetic even if we started out with `void*`.
- Full code with some test examples:
- ```c
- #include <string.h>
- #include <stdio.h>
- char* strnul (char* s)
- {
- return (s + strlen(s));
- }
- const char* strnulc (const char* s)
- {
- return (s + strlen(s));
- }
- #define strnul(s) \
- _Generic((s), \
- char*: strnul, \
- const char*: strnulc)(s)
- int main()
- {
- char str[] = "hello";
- const char* strc = str;
- printf("Pos: %td\n", strnul(str) - str);
- printf("Pos: %td\n", strnul(strc) - strc);
- printf("Pos: %td\n", strnul(str+2) - str);
- }
- ```
- A function is the obvious solution since it only comes with one evaluation per argument before the function is called.
- If the only rationale for using macros over functions is to avoid casts, then just make the macro a wrapper macro for the function calls, similar to how a C standard lib will have to implement _QVoid_ and _QChar_ fictional types in C23.
- Assuming we do not allow implicit `void` pointer conversions (for the same reason as we don't allow casts - type safety), then:
- ```c
- #include <string.h>
- char* strnul (char* s)
- {
- return (s + strlen(s));
- }
- const char* strnulc (const char* s)
- {
- return (s + strlen(s));
- }
- #define strnul(s) \
- _Generic((s), \
- char*: strnul, \
- const char*: strnulc)(s)
- ```
- If `void` pointers should be allowed then simply add `void*: strnul` to `_Generic` (and one for `const void*` too). The implicit conversion to `char*` also means we can do standard-compliant pointer arithmetic even if we started out with `void*`.
- Full code with some test examples:
- ```c
- #include <string.h>
- #include <stdio.h>
- char* strnul (char* s)
- {
- return (s + strlen(s));
- }
- const char* strnulc (const char* s)
- {
- return (s + strlen(s));
- }
- #define strnul(s) \
- _Generic((s), \
- char*: strnul, \
- const char*: strnulc)(s)
- int main()
- {
- char str[] = "hello";
- const char* strc = str;
- printf("Pos: %td\n", strnul(str) - str);
- printf("Pos: %td\n", strnul(strc) - strc);
- printf("Pos: %td\n", strnul(str+2) - str);
- }
- ```
#1: Initial revision
If the only rationale for using macros over functions is to avoid casts, then just make the macro a wrapper macro for the function calls, similar to how a C standard lib will have to implement _QVoid_ and _QChar_ fictional types in C23.
Assuming we do not allow implicit `void` pointer conversions (for the same reason as we don't allow casts - type safety), then:
```c
#include <string.h>
char* strnul (char* s)
{
return (s + strlen(s));
}
const char* strnulc (const char* s)
{
return (s + strlen(s));
}
#define strnul(s) \
_Generic((s), \
char*: strnul, \
const char*: strnulc)(s)
```
If `void` pointers should be allowed then simply add `void*: strnul` to `_Generic` (and one for `const void*` too). The implicit conversion to `char*` also means we can do standard-compliant pointer arithmetic even if we started out with `void*`.
Full code with some test examples:
```c
#include <string.h>
#include <stdio.h>
char* strnul (char* s)
{
return (s + strlen(s));
}
const char* strnulc (const char* s)
{
return (s + strlen(s));
}
#define strnul(s) \
_Generic((s), \
char*: strnul, \
const char*: strnulc)(s)
int main()
{
char str[] = "hello";
const char* strc = str;
printf("Pos: %td\n", strnul(str) - str);
printf("Pos: %td\n", strnul(strc) - strc);
printf("Pos: %td\n", strnul(str+2) - str);
}
```
