Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best way to emulate __typeof__ for msvc or alternative workaround?

I have some code

#define DEBUG_PRINT(x,...) \
    do \
    {\
        _Pragma("GCC diagnostic push") \
        _Pragma("GCC diagnostic ignored \"-Wunused-value\"") \
        __typeof__((0,x)) _x = x; \
        _Pragma("GCC diagnostic pop") \
        DEBUG_PRINT_PTR((#x), &_x, __VA_ARGS__);\
    } while(0)


//The repetition of debug_print_printf_specifier is to avoid repetition for custom types.
#define DEBUG_PRINT_PTR(xstr, xp,...) \
_Generic((*xp), \
const char *: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
char *: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
int: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
float: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
double: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
char: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
int16_t: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
uint16_t: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
uint32_t: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
int64_t: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
uint64_t: debug_print_printf_specifier(xstr, (void *)xp, TYPE_PTR_TO_PRINTF_SPECIFIER(xp), __FILE__, __LINE__, _my_func__, debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__}))),\
default: DEBUG_PRINT_CUSTOM_TYPE(xstr, xp, __VA_ARGS__))

#define DEBUG_PRINT_CUSTOM_TYPE(xstr, xp,...) \
debug_print_custom_to_debug_string(xstr, xp, &((dsc_func_ptr){GET_CREATE_DEBUG_STRING_FUNC(xp)}), __FILE__, __LINE__, _my_func__,\
debug_print_options_apply_group_options(&((debug_print_options){__VA_ARGS__})))



#define GET_CREATE_DEBUG_STRING_FUNC(x) _Generic((x), \
debug_print_options *: debug_print_options_to_debug_string, \
debug_print_group_options *: debug_print_group_options_to_debug_string, \
default: print_not_valid_type_for_debug_print)

I need a pointer to x in DEBUG_PRINT which may be a variable or an expression. To support expressions I assign it to a temporary and then take the address of that. I could emulate __typeof__ with _Generic for a limited set of types but then users would need to add lines for custom types in 2 places. Is there any other way to do this? I'd be ok with only supporting the latest Microsoft C compiler.

like image 662
Roman A. Taycher Avatar asked Mar 31 '15 21:03

Roman A. Taycher


People also ask

Is GCC faster than Msvc?

GCC is a fine compiler, and can produce code that has pretty much the same performance, if not better, than MSVC.

Is MSVC compiler good?

Microsoft Visual Studio is a good compiler for developing Windows applications. Although Visual Studio presents a ton of choices to the user when first starting out (for instance, there are a lot of different project types), the amount of choice gives a good idea of the overall scope of this tool.

What compiler does Msvc use?

Microsoft C++ Compiler (MSVC) This is the default compiler for most Visual Studio C++ projects and is recommended if you are targeting Windows.


1 Answers

If you are using a recent version of MSVC, it supports the new C standards, so you can use _Generic on it.

Otherwise, for old versions, it depends on how you are compiling your code. If you are actually using the C mode of Visual Studio (i.e. /Tc or compiling a file with .c extension, which implies /Tc), and you cannot use the C++ mode (e.g. the code is in a header), then you are out of luck since MSVC does not support C11 (and therefore you cannot even use _Generic to emulate it).

However, if you are compiling in C++ mode (or you can take that luxury), then you can take advantage of decltype as @MooingDuck suggested (in recent versions of Visual Studio, e.g. 2017):

#include <stdio.h>  #ifdef __cplusplus #    define TEMPORARY(x) decltype((x)) _x = (x); #else #    define TEMPORARY(x) __typeof__((x)) _x = (x); #endif  #define DEBUG_PRINT(x) \     do { \         TEMPORARY(x); \         printf("%s = %p\n", #x, &_x); \     } while(0)  void f() {     int y = 100;     DEBUG_PRINT(123);     DEBUG_PRINT(y + 123); } 

Take a look at the generated code for gcc 7.3 (-std=c99 -Wall -Wextra) and MSVC 2017 (/std:c++14 /W4), which both seem fine and equivalent: https://godbolt.org/g/sdWAv7

like image 86
Acorn Avatar answered Sep 28 '22 02:09

Acorn