R
R
RR_Zz2020-07-24 00:39:30
C++ / C#
RR_Zz, 2020-07-24 00:39:30

Why does a warning appear in _Generic on cast when overloading a function through a macro?

There is a code in which a function is overloaded through a macro.

The compiler issues a warning on cast variables, but the compiled program works correctly.
Suppressing warnings is not an option.

I would like to know the reason for the warnings, is this the standard behavior or the imperfection of the preprocessor?

Minimum code for testing and experimentation.

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
 
#define FNK(...) \
        FFF_x(, \
                ##__VA_ARGS__, \
                FFF_B(__VA_ARGS__), \
                FFF_A(__VA_ARGS__), \
                FFF_0(__VA_ARGS__))
 
#define FFF_x(x, A, B, FFF, ...)FFF
 
#define FFF_0() fnk(0, 0, NULL)
#define FFF_A(A) fnk(A, 0, NULL)
 
#define FFF_B(A, BC) \
        _Generic((A), \
                int : _Generic((BC), \
                        int : fnk(A, BC, NULL), \
                        char * : fnk(A, 0, BC)))
 
void fnk(uintmax_t A, uintmax_t B, char* C){
    printf("A : %"PRIXMAX"\n", A);
    printf("B : %"PRIXMAX"\n", B);
    printf("C : \"%s\"\n", C);
}
 
void fnk_test(void){
    printf("\n0)---------\n");
    FNK();
 
    printf("\n1)---------\n");
    FNK(1);
 
    printf("\n2.1)---------\n");
    FNK(1, 2);
 
    printf("\n2.2)---------\n");
    FNK(1, "2");
}
 
int main() {
    fnk_test();
    return 0;
}


In FNK(1, 2); -- swears that the variable is not char *
, but
in FNK(1, "2"); -- on the contrary, which is not int.

Program output:
0)---------
A : 0
B : 0
C : "(null)"
 
1)---------
A : 1
B : 0
C : "(null)"
 
2.1)---------
A : 1
B : 2
C : "(null)"
 
2.2)---------
A : 1
B : 0
C : "2"

Warnings:
5f1a02eb5bb9f426989446.png

Answer the question

In order to leave comments, you need to log in

1 answer(s)
J
jcmvbkbc, 2020-07-24
@RR_Zz

I would like to know the reason for the warnings, is this the standard behavior or the imperfection of the preprocessor?

The preprocessor has nothing to do with it. If you look in
preprocessed code,

_Generic((1), int : _Generic((2), int : fnk(1, 2,
# 37 "generic.c" 3 4
   ((void *)0)
# 37 "generic.c"
   ), char * : fnk(1, 0, 2)));

    printf("\n2.2)---------\n");
    _Generic((1), int : _Generic(("2"), int : fnk(1, "2",
# 40 "generic.c" 3 4
   ((void *)0)
# 40 "generic.c"
   ), char * : fnk(1, 0, "2")));

then you can see that the expression selected by _Generic has the correct types, but the expressions in other branches have the wrong types. Warning about this.
It could be fixed by starting two different functions for int and char * and selecting only the desired function in _Generic, and not the entire expression. Something like that:
void fnk_int(uintmax_t A, uintmax_t B){
...
}
void fnk_pchar(uintmax_t A, char *B){
...
}

#define FFF_B(A, BC) \
        _Generic((A), \
                int : _Generic((BC), \
                        int : fnk_int, \
                        char * : fnk_pchar)(A, BC))

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question