ISO C equivalent of braced-groups within expressions - c

How can I do the following in a compliant (ISO C99) way?
#define MALLOC(type, length, message) ({ \
type * a_##__LINE__ = (type *)malloc((length) * sizeof(type)); \
assert(message && (a_##__LINE__ != NULL)); \
a_##__LINE__; \
})
double **matrix = MALLOC(double *, height, "Failed to reserve");
NB: to compile I use: gcc -std=c99 -pedantic ...

You shouldn't put the test for malloc() in an assert(): it won't be compiled in when you do a release build. I haven't used assert() in the following program.
#include <stdio.h>
#include <stdlib.h>
void *mymalloc(size_t siz, size_t length,
const char *message, const char *f, int l) {
void *x = malloc(siz * length);
if (x == NULL) {
fprintf(stderr, "a.out: %s:%d: MALLOC: "
"Assertion `\"%s\" && x != ((void *)0)' failed.\n",
f, l, message);
fprintf(stderr, "Aborted\n");
exit(EXIT_FAILURE);
}
return x;
}
#define MALLOC(type, length, message)\
mymalloc(sizeof (type), length, message, __FILE__, __LINE__);
int main(void) {
int height = 100;
double **matrix = MALLOC(double *, height, "Failed to reserve");
/* work; */
free(matrix);
return 0;
}

There is no standard equivalent to the GCC extension you are using.
You can achieve the equivalent result using a function (possibly even an inline function if you are using C99) in place of the code in the macro. You still need a macro to invoke that function because one of the arguments is a 'type name' and you can't pass those to functions.
See the answer by #pmg for an illustration of the type of function and macro using it.

Related

Can I cast a variable to a type decided during execution in C

int* push_back_int(intVector* target, int push)
{
target->length++;
target->val = (int *)realloc(target->val, target->length * sizeof(int));
target->val[target->length - 1] = push;
return &target->val[target->length - 1];
}
float* push_back_float(floatVector* target, float push)
{
target->length++;
target->val = (float *)realloc(target->val, target->length * sizeof(float));
target->val[target->length - 1] = push;
return &target->val[target->length - 1];
}
Is there any way that I can hold a variable to replace the cast to int* or float* so that i can reuse the same code for multiple variable types using void*
No. In C the type is only available at compile-time.
You can use void * to pass data back and forth but you need to retain the element size. This approach is referred to as non-type safe (compiler will not catch the wrong "type", say, switching iq and fq below, which will then blow up most impressively at run-time when you get it wrong). Note how calling code handles the cast.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct queue {
size_t push_length;
void *val;
size_t length;
};
void *push_back(struct queue *target, void *push) {
size_t offset = target->length * target->push_length;
target->length++;
void *tmp = realloc(target->val, target->length * target->push_length);
if(!tmp) {
// error handling
return NULL;
}
target->val = tmp;
return memcpy((char *) target->val + offset, push, target->push_length);
}
int main() {
struct queue fq = { sizeof(float), NULL, 0 };
push_back(&fq, &(float) { 2.718 });
push_back(&fq, &(float) { 3.142 });
for(unsigned i = 0; i < fq.length; i++) {
printf("%u: %f\n", i, ((float *) fq.val)[i]);
}
struct queue iq = { sizeof(int), NULL, 0 };
push_back(&iq, &(int) { 1 });
push_back(&iq, &(int) { 2 });
for(unsigned i = 0; i < iq.length; i++) {
printf("%u: %d\n", i, ((int *) iq.val)[i]);
}
}
and the output:
0: 2.718000
1: 3.142000
0: 1
1: 2
Your platform may require specific alignment for each element of val (i.e. for type T push_length = sizeof(T) % alignof(T) ? (sizeof(T) / alignof(T) + 1) * alignof(T) : sizeof(T)).
Can I cast a variable to a type decided during execution (?)
Yes, in some cases that support variable length array.
(double (*)[r]) is a cast to a type determined at run time. Demonstrative code follows:
int r = rand();
double a[r];
double (*b)[r] = &a;
unsigned char *data = malloc(sizeof a);
b = data; // warning: assignment to 'double (*)[r]' from incompatible pointer type 'unsigned char *' [-Wincompatible-pointer-types]
b = (double (*)[r]) data; // OK
(void) b;
In OP's code, the cast nor the sizeof(type) are not needed.
Use target->val = realloc(target->val, target->length * sizeof(target->val[0])); for both.
Only difference remaining in push_back_...() is the function name and signature.
Is there any way that I can hold a variable to replace the cast to int* or float* so that i can reuse the same code for multiple variable types using void*.
Any object pointer can be held in a void *. Yet that void * does not certainly retain anything to denote the type from which it is assigned. Auxiliary data needed. In OP's case, the size of the type would be enough if the size was consistent per vector.
typedef struct {
size_t object_size;
size_t length;
void *val;
} gVector;
// Pass in the address of the object to push
void* push_back_g(gVector* target, const void *push) {
void *p = realloc(target->val, target->object_size * (target->length + 1u));
if (p) {
target->val = p;
return memcpy((unsigned char *)val + target->object_size * target->length++,
push, target->object_size);
}
// Handle error with TBD code
return NULL;
}
Alternative we could pass in the size per push call and store that too.
Yet in both cases, code loses type checking.
With _Generic, code could handle various pre-determined select types with common code. Yet it seems OP wants any type.
C does not have runtime type information (RTTI) so you would have to hack that out manually by introducing an enum or similar. However, I would not encourage type generic programming with enums + void pointers in modern C programming since it is type unsafe and clunky.
We could use macros to generate type-generic code based on a number of supported types, kind of like a poor man's version of C++ templates. But that creates code which is very hard to read and maintain, so it isn't advisable either. Just for the record, it might look like this:
// NOT RECOMMENDED PRACTICE
#define SUPPORTED_TYPES(X) \
X(int) \
X(float) \
#define vector_define(type) \
typedef struct \
{ \
type* val; \
size_t length; \
}type##Vector;
SUPPORTED_TYPES(vector_define)
#define push_back_define(type) \
type* push_back_##type (type##Vector* target, type push) \
{ \
target->length++; \
target->val = realloc(target->val, target->length * sizeof(type)); \
target->val[target->length - 1] = push; \
return &target->val[target->length - 1]; \
}
SUPPORTED_TYPES(push_back_define)
As you can see it starts to look like a different language and the code is pretty alien to read for anyone who isn't used at seeing "X-macros".
In this case the best solution is perhaps to write a version using void* but to wrap it in a type safe macros utilizing _Generic. Your vector could then be implemented as a single type-generic ADT. Not a separate one for int, float and so on. As for how to do that proper, it's too long an answer for SO - a place to start would be to read up on How to do private encapsulation in C?.
A simple example of how to use _Generic without creating a proper ADT:
#include <stdio.h>
void push_back_int (int* target, int push)
{ puts(__func__); }
void push_back_float (float* target, float push)
{ puts(__func__); }
#define push_back(arr,item) \
_Generic((arr), \
int*: push_back_int, \
float*: push_back_float) \
((arr), (item) )
int main (void)
{
int* i_arr;
int i_item = 5;
push_back(i_arr, i_item);
float* f_arr;
float f_item = 123.0f;
push_back(f_arr, f_item);
}

macro parameter won't take argument passed (nvcc)

I'm just starting to code on CUDA and I'm trying to manage my codes into a bunch of different files, but one of my macros won't take the argument passed for some reason.
The error is:
addkernel.cu(19): error: identifier "err" is undefined
so my main code is in ../cbe4/addkernel.cu
#include <stdio.h>
#include <stdlib.h>
#include "cbe4.h"
#include "../mycommon/general.h"
#define N 100
int main( int argc, char ** argv ){
float h_out[N], h_a[N], h_b[N];
float *d_out, *d_a, *d_b;
for (int i=0; i<N; i++) {
h_a[i] = i + 5;
h_b[i] = i - 10;
}
// The error is on the next line
CUDA_ERROR( cudaMalloc( (void **) &d_out, sizeof(float) * N ) );
CUDA_ERROR( cudaMalloc( (void **) &d_a, sizeof(float) * N ) );
CUDA_ERROR( cudaMalloc( (void **) &d_b, sizeof(float) * N ) );
cudaFree(d_a);
cudaFree(d_b);
return EXIT_SUCCESS;
}
The macro is defined in ../mycommon/general.h:
#ifndef __GENERAL_H__
#define __GENERAL_H__
#include <stdio.h>
// error checking
void CudaErrorCheck (cudaError_t err, const char *file, int line);
#define CUDA_ERROR ( err ) (CudaErrorCheck( err, __FILE__, __LINE__ ))
#endif
and this is the source code for the function CudaErrorCheck in ../mycommon/general.cu:
#include <stdio.h>
#include <stdlib.h>
#include "general.h"
void CudaErrorCheck (cudaError_t err,
const char *file,
int line) {
if ( err != cudaSuccess ) {
printf( "%s in %s at line %d \n",
cudaGetErrorString( err ),
file, line );
exit( EXIT_FAILURE );
}
}
../cbe/cbe4.h is my header file and ../cbe/cbe4.cu the source file for kernel codes (in case this might help):
in cbe4.h:
__global__
void add( float *, float *, float * );
in cbe4.cu:
#include "cbe4.h"
__global__ void add( float *d_out, float *d_a, float *d_b ) {
int tid = (blockIdx.x * blockDim.x) + threadIdx.x;
d_out[tid] = d_a[tid] + d_b[tid]; }
and here's my makefile (stored in ../cbe4):
NVCC = nvcc
SRCS = addkernel.cu cbe4.cu
HSCS = ../mycommon/general.cu
addkernel:
$(NVCC) $(SRCS) $(HSCS) -o $#
Also, I'm using the Cuda by Example book, by the way. One thing about the code in common/book.h, the function for HandleError ( I renamed it CudaErrorCheck and placed it in another source code here ) was defined in the header file (equivalently, at the CudaErrorCheck declaration in my general.h . Isn't this inadvisable? Or so I heard. )
Spacing matters in macro definitions. You have:
#define CUDA_ERROR ( err ) (CudaErrorCheck( err, __FILE__, __LINE__ ))
You need (minimal change — delete one space):
#define CUDA_ERROR( err ) (CudaErrorCheck( err, __FILE__, __LINE__ ))
With a function-like macro, there cannot be white space between the macro name and the open parenthesis of the argument list of the macro definition. When it comes to using the macro, white space is allowed between the macro name and the open parenthesis of the argument list.
I'd write:
#define CUDA_ERROR(err) CudaErrorCheck(err, __FILE__, __LINE__)
The extra parentheses around the whole expansion aren't really necessary, and I don't much like white space around parentheses. Different people have different views on this, so I'm stating my preference without in any sense demanding that you use it (but obviously suggesting that you consider it).
Because of the space, your code was expanding to look like:
( err ) (CudaErrorCheck( err, "addkernel.cu", 19 ))( cudaMalloc( (void **) &d_out, sizeof(float) * N ) );
and err was diagnosed as an undefined identifier, making the cast invalid.

Function overloading in C without using _Generic

I wish to accomplish function overloading in C, but I am attempting to run my code on a Unix server that does not have C11 support therefore the _Generic keyword is not available.
(Upgrading the server so it has a newer version of GCC is not an option).
Are there any alternatives to using _Generic to simulate effective function overloading in C?
You can do a limited form of overloading, for some argument types, like so:
void func_int(int);
void func_long(long);
void func_longlong(long long);
#define FUNC(X) \
(sizeof(X) <= sizeof(int) ? func_int(X) \
: sizeof(X) == sizeof(long) ? func_long(X) \
: func_longlong(X))
This will allow you to use FUNC(i) and have it call different functions. It's limited, because you can only distinguish types by their size. That means if sizeof(int) == sizeof(long) then you will never call func_long, and if sizeof(long) == sizeof(long long) then you will never call func_longlong. Also, you can't overload for other types, such as double, if sizeof(double) is the same as one of the integer types you're testing for.
It can be used to overload for e.g. float, double or long double, where you might have different implementations of a function that calculate more or less precisely depending on the precision (i.e. number of bits) in the argument type.
The GCC manual explicitly shows a GNU99 (-std=gnu99) workaround since at least version 3.1.1.
There are limitations, of course: all variants must have the same return type, and all function variants must make syntactic sense. The latter is often the cause of various compile errors (invalid types for function variant parameters). That can be avoided by declaring the functions without parameter prototypes; however, one must then remember that default type promotions will then take place (float are promoted to double, and all integer types smaller than int are promoted to int or unsigned int). Consider this example program:
#define _GNU_SOURCE /* for asprintf() */
#include <stdlib.h>
#include <stdio.h>
typedef struct {
double x;
double y;
double z;
double d;
} plane;
static const char *foo_char_array();
static const char *foo_int();
static const char *foo_long();
static const char *foo_double();
static const char *foo_float();
static const char *foo_short();
static const char *foo_plane();
#define foo(x) \
( __builtin_choose_expr( __builtin_types_compatible_p(typeof(x), int), foo_int(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), long), foo_long(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), short), foo_short(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), float), foo_float(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), double), foo_double(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), plane), foo_plane(x), \
__builtin_choose_expr( __builtin_types_compatible_p(typeof(x), char []), foo_char_array(x), \
(void)0 ))))))) )
int main(void)
{
double d = 1.0;
float f = 2.0f;
short s = 3;
long n = 4L;
plane p = { 5.0, 6.0, 7.0, 8.0 };
printf("foo(9) = %s\n", foo(9));
printf("foo(10L) = %s\n", foo(10L));
printf("foo(11.0f) = %s\n", foo(11.0f));
printf("foo(12.0) = %s\n", foo(12.0));
printf("foo(\"bar\") = %s\n", foo("bar"));
printf("foo(d) = %s\n", foo(d));
printf("foo(f) = %s\n", foo(f));
printf("foo(s) = %s\n", foo(s));
printf("foo(n) = %s\n", foo(n));
printf("foo(p) = %s\n", foo(p));
return EXIT_SUCCESS;
}
static const char *foo_char_array(char x[]) { return "char []"; }
static const char *foo_int(int x) { static char buffer[40]; snprintf(buffer, sizeof buffer, "(int)%d", x); return (const char *)buffer; }
static const char *foo_long(long x) { static char buffer[40]; snprintf(buffer, sizeof buffer, "(long)%ld", x); return (const char *)buffer; }
static const char *foo_float(double x) { static char buffer[40]; snprintf(buffer, sizeof buffer, "%af", x); return (const char *)buffer; }
static const char *foo_double(double x) { static char buffer[40]; snprintf(buffer, sizeof buffer, "%a", x); return (const char *)buffer; }
static const char *foo_short(int x) { static char buffer[40]; snprintf(buffer, sizeof buffer, "(short)%d", x); return (const char *)buffer; }
static const char *foo_plane(plane p) { static char buffer[120]; snprintf(buffer, sizeof buffer, "(plane){ .x=%g, .y=%g, .z=%g, .d=%g }", p.x, p.y, p.z, p.d); return (const char *)buffer; }
You do not need to determine the type based on a single parameter; you can do e.g. __builtin_types_compatible_p(typeof(x), double) && __builtin_types_compatible_p(typeof(y), double) to verify both x and y are of type double.
When compiled and run, the above program will output
foo(9) = (int)9
foo(10L) = (long)10
foo(11.0f) = 0x1.6p+3f
foo(12.0) = 0x1.8p+3
foo("bar") = char []
foo(d) = 0x1p+0
foo(f) = 0x1p+1f
foo(s) = (short)3
foo(n) = (long)4
foo(p) = (plane){ .x=5, .y=6, .z=7, .d=8 }
tested on 32-bit x86 Linux (ILP32), as well as on x86-64 (LP64). And yes, the above program will leak memory, since it never free()s the dynamically allocated strings returned by the foo_..() function variants.
I found a method that appears to work, however I still get a couple warnings at compile time...
Working code:
#include <stdio.h>
#define print(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int(x) , \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string(x), \
(void)0))
void print_int(int i) {
printf("int: %d\n", i);
}
void print_string(char* s) {
printf("char*: %s\n", s);
}
int main(int argc, char* argv[]) {
print(1);
print("this");
return 0;
}
output:
int: 1
char*: thing
Compiler warnings:
gcc overload.c -o main
overload.c: In function 'main':
overload.c:19: warning: passing argument 1 of 'print_string' makes pointer from integer without a cast
overload.c:20: warning: passing argument 1 of 'print_int' makes integer from pointer without a cast
It is somehow possible using function pointers, and nameless struct inside a union. Here comes an example in which we overload the add and mul functions. There are two unions LIBI, and LIBF containing nameless structures. LIBI contains the function pointers add and mulc which only use integer values. LIBF is the same as LIBI except that add and mul use float variables. In addition, we need to create addi, muli, addf, and mulf functions outside of these unions. Functions pointers in unions will be referred to these 4 functions. For example, add in LIBI is referred to addi because addi uses int values and add in LIBF is referred to addf as it uses only float variables. This example can also be used as a way of emulating namespace in C which is absent in the language. Unions act like the namespace in this example.
#include<stdio.h>
#include<stdlib.h>
union {
struct {
void (*add)(int *, int);
void (*mul)(int *, int);
};
}LIBI;
union {
struct {
void (*add)(float *, float);
void (*mul)(float *, float);
};
}LIBF;
void addi(int *a, int c){
*a += c;
}
void addf(float *a, float c){
*a += c;
}
void muli(int *a, int c){
*a *= c;
}
void mulf(float *a, float c){
*a *= c;
}
int main(void){
LIBI.add = addi;
LIBF.add = addf;
LIBI.mul = muli;
LIBF.mul = mulf;
int ia = 10;
int ib = 2;
float fa = 20.0f;
float fb = 2.0f;
LIBI.add(&ia,ib);
LIBF.add(&fa,fb);
printf("%d\n",ia);
printf("%f\n",fa);
LIBI.mul(&ia,ib);
LIBF.mul(&fa,fb);
printf("%d\n",ia);
printf("%f\n",fa);
return 0;
}

Function overloading in C using GCC - compiler warnings

I am attempting to implement function overloading in C, and I am very close. I am using C99 so the _Generic keyword introduced in C11 is not available to me. I have developed some working code, but when I compile it I get a couple warnings.
Working example:
#include <stdio.h>
#define print(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int(x) , \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string(x), \
(void)0))
void print_int(int i) {
printf("int: %d\n", i);
}
void print_string(char* s) {
printf("char*: %s\n", s);
}
int main(int argc, char* argv[]) {
print(1);
print("this");
return 0;
}
Compiling creates the following warnings:
gcc overload.c -o main
overload.c: In function 'main':
overload.c:19: warning: passing argument 1 of 'print_string' makes pointer from integer without a cast
overload.c:20: warning: passing argument 1 of 'print_int' makes integer from pointer without a cast
For a little more debugging information, here is what the main function looks like after the preprocessor does its work:
int main(int argc, char* argv[]) {
__builtin_choose_expr(__builtin_types_compatible_p(typeof(1), int ), print_int(1) , __builtin_choose_expr(__builtin_types_compatible_p(typeof(1), char[]), print_string(1), (void)0));
__builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), int ), print_int("this") , __builtin_choose_expr(__builtin_types_compatible_p(typeof("this"), char[]), print_string("this"), (void)0));
return 0;
}
How can I make the compilation warnings go away and still have working code?
In theory, this should work:
#define print(x) \
(__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \
(void)0))(x))
It chooses either print_int or print_string, then applies the chosen function to x.
The GNU page on the build-ins says that the branches not chosen may still generate syntax errors, but I fail to see how mismatched types are syntax errors.
Anyway, you can get rid of the warnings when you move the arguments to the function out of the type-dependent choice. So (in pseudocode in order to make it more readable), instead of
choose_type_of(x, int, print_int(x),
choose_type_of(x, char[], print_string(x), (void) 0))
do
choose_type_of(x, int, print_int,
choose_type_of(x, char[], print_string, pass))(x)
That's what user2357112 suggested in a comment. I was working on a similar solution, but I had a hard time to get the default part (the pass above) to work. When I use (void), which should then expand to (void)(x), I get an error about an unmatched parenthesis.
The solution below creates a default printing function that doesn't use its arguments. It could probably be a non-existent function, so that there are problems when linking or something else that produces an error.
#include <stdio.h>
#define print(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \
int), print_int, \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), \
const char[]), print_string, \
print_any))(x)
void print_int(int i) {
printf("int: %d\n", i);
}
void print_string(const char *s) {
printf("char[]: %s\n", s);
}
void print_any() {
printf("unknown\n");
}
int main(void)
{
int n = 9;
const char str[] = "hello";
print(n);
print(str);
print(1);
print("this");
print(3.2);
return 0;
}
Here's an example with several methods that achieve function overloading.
One poster mentioned this
The GNU page on the build-ins says that the branches not chosen may
still generate syntax errors, but I fail to see how mismatched types
are syntax errors.
The syntax errors they're referring to I believe are the compiler warnings you get because after preprocessing the compiler can see that the types of the arguments to some functions, even though they can never be called are wrong. The solution (which I think is quite neat) is to find a way to hide the types from the compiler. The obvious way is varargs, the less obvious way is is the current answer to the OP's question.
Caveats apply ie not all solutions are type safe and this is entirely specific to GNU...
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#define print(x) \
(__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int , \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string, \
(void)0))(x))
#define print1(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), print_int1(1,x) , \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), print_string1(1,x), \
(void)0))
#define print2(x) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), int ), printer(1,x), \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(x), char[]), printer(2,x), \
(void)0))
#define TYPE_ID(x) __builtin_types_compatible_p(typeof(x), int ) * 1 \
+ __builtin_types_compatible_p(typeof(x), char[]) * 2
#define print3(x) printer(TYPE_ID(x), x)
#define STATIC_ASSERT(COND,MSG) typedef char static_assertion_##MSG[(COND)?1:-1]
#define print4(x) \
STATIC_ASSERT(TYPE_ID(x), __LINE__); \
printer(TYPE_ID(x), x)
void printer(int i, ...) {
va_list v;
va_start(v, i);
switch(i) {
case 1:{
int arg = va_arg(v, int);
printf("int: %d\n", arg);
va_end(v);
break;
}
case 2:{
char * arg = va_arg(v, char*);
printf("char*: %s\n", arg);
va_end(v);
break;
}
default: {
fprintf(stderr, "Unknown type, abort\n");
abort();
}
}
}
void print_int(int i) {
printf("int: %d\n", i);
}
void print_string(char* s) {
printf("char*: %s\n", s);
}
void print_int1(int i, ...) {
va_list v;
va_start(v, i);
int arg = va_arg(v, int);
printf("int: %d\n", arg);
va_end(v);
}
void print_string1(int i, ...) {
va_list v;
va_start(v, i);
char * arg = va_arg(v, char*);
printf("char*: %s\n", arg);
va_end(v);
}
int main(int argc, char* argv[]) {
int var = 1729;
double var1 = 1729;
//Type safe
//print(var1);//Comple time error
print(var);
print("print");
/* Following are not Type Safe */
print1(var1);// BAD... Does nothing.
print1(var);
print1("print1");
print2(var1);// BAD... Does nothing.
print2(var);
print2("print2");
//print3(var1);//Evil... Runtime error
print3(var);
print3("print3");
//Type Safe
//print4(var1);//Comple time error
print4(var);
print4("print4");
return 0;
}
Source is on github...
https://github.com/harryjackson/doc/blob/master/c/overload_c_functions.c
The switch method with multiple arguments can be found here...
http://locklessinc.com/articles/overloading/
The whole
The warning can be suppressed by doing some type casting in the #define section, but I feel like this probably is not the best or even a good solution at all...
Change the function calls in the #define section to this:
print_string((char*)x)
print_int((int)x)
I really hope someone comes up with a better solution though, because this just feels wrong...

Passing variable number of arguments around

Say I have a C function which takes a variable number of arguments: How can I call another function which expects a variable number of arguments from inside of it, passing all the arguments that got into the first function?
Example:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
To pass the ellipses on, you initialize a va_list as usual and simply pass it to your second function. You don't use va_arg(). Specifically;
void format_string(char *fmt,va_list argptr, char *formatted_string);
void debug_print(int dbg_lvl, char *fmt, ...)
{
char formatted_string[MAX_FMT_SIZE];
va_list argptr;
va_start(argptr,fmt);
format_string(fmt, argptr, formatted_string);
va_end(argptr);
fprintf(stdout, "%s",formatted_string);
}
There's no way of calling (eg) printf without knowing how many arguments you're passing to it, unless you want to get into naughty and non-portable tricks.
The generally used solution is to always provide an alternate form of vararg functions, so printf has vprintf which takes a va_list in place of the .... The ... versions are just wrappers around the va_list versions.
Variadic Functions can be dangerous. Here's a safer trick:
void func(type* values) {
while(*values) {
x = *values++;
/* do whatever with x */
}
}
func((type[]){val1,val2,val3,val4,0});
In magnificent C++11 you could use variadic templates:
template <typename... Ts>
void format_string(char *fmt, Ts ... ts) {}
template <typename... Ts>
void debug_print(int dbg_lvl, char *fmt, Ts... ts)
{
format_string(fmt, ts...);
}
Though you can solve passing the formatter by storing it in local buffer first, but that needs stack and can sometime be issue to deal with. I tried following and it seems to work fine.
#include <stdarg.h>
#include <stdio.h>
void print(char const* fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
}
void printFormatted(char const* fmt, va_list arg)
{
vprintf(fmt, arg);
}
void showLog(int mdl, char const* type, ...)
{
print("\nMDL: %d, TYPE: %s", mdl, type);
va_list arg;
va_start(arg, type);
char const* fmt = va_arg(arg, char const*);
printFormatted(fmt, arg);
va_end(arg);
}
int main()
{
int x = 3, y = 6;
showLog(1, "INF, ", "Value = %d, %d Looks Good! %s", x, y, "Infact Awesome!!");
showLog(1, "ERR");
}
Hope this helps.
You can try macro also.
#define NONE 0x00
#define DBG 0x1F
#define INFO 0x0F
#define ERR 0x07
#define EMR 0x03
#define CRIT 0x01
#define DEBUG_LEVEL ERR
#define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: "
#define WHEREARG __FILE__,__func__,__LINE__
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define DEBUG_PRINT(X, _fmt, ...) if((DEBUG_LEVEL & X) == X) \
DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__)
int main()
{
int x=10;
DEBUG_PRINT(DBG, "i am x %d\n", x);
return 0;
}
You can use inline assembly for the function call. (in this code I assume the arguments are characters).
void format_string(char *fmt, ...);
void debug_print(int dbg_level, int numOfArgs, char *fmt, ...)
{
va_list argumentsToPass;
va_start(argumentsToPass, fmt);
char *list = new char[numOfArgs];
for(int n = 0; n < numOfArgs; n++)
list[n] = va_arg(argumentsToPass, char);
va_end(argumentsToPass);
for(int n = numOfArgs - 1; n >= 0; n--)
{
char next;
next = list[n];
__asm push next;
}
__asm push fmt;
__asm call format_string;
fprintf(stdout, fmt);
}
Ross' solution cleaned-up a bit. Only works if all args are pointers. Also language implementation must support eliding of previous comma if __VA_ARGS__ is empty (both Visual Studio C++ and GCC do).
// pass number of arguments version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);}
// NULL terminated array version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);}
Short answer
/// logs all messages below this level, level 0 turns off LOG
#ifndef LOG_LEVEL
#define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif
#define _LOG_FORMAT_SHORT(letter, format) "[" #letter "]: " format "\n"
/// short log
#define log_s(level, format, ...) \
if (level <= LOG_LEVEL) \
printf(_LOG_FORMAT_SHORT(level, format), ##__VA_ARGS__)
usage
log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");
output
[1]: fatal error occurred
[3]: x=2 and name=ali
log with file and line number
const char* _getFileName(const char* path)
{
size_t i = 0;
size_t pos = 0;
char* p = (char*)path;
while (*p) {
i++;
if (*p == '/' || *p == '\\') {
pos = i;
}
p++;
}
return path + pos;
}
#define _LOG_FORMAT(letter, format) \
"[" #letter "][%s:%u] %s(): " format "\n", _getFileName(__FILE__), __LINE__, __FUNCTION__
#ifndef LOG_LEVEL
#define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif
/// long log
#define log_l(level, format, ...) \
if (level <= LOG_LEVEL) \
printf(_LOG_FORMAT(level, format), ##__VA_ARGS__)
usage
log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");
output
[1][test.cpp:97] main(): fatal error occurred
[3][test.cpp:98] main(): x=2 and name=ali
custom print function
you can write custom print function and pass ... args to it and it is also possible to combine this with methods above. source from here
int print_custom(const char* format, ...)
{
static char loc_buf[64];
char* temp = loc_buf;
int len;
va_list arg;
va_list copy;
va_start(arg, format);
va_copy(copy, arg);
len = vsnprintf(NULL, 0, format, arg);
va_end(copy);
if (len >= sizeof(loc_buf)) {
temp = (char*)malloc(len + 1);
if (temp == NULL) {
return 0;
}
}
vsnprintf(temp, len + 1, format, arg);
printf(temp); // replace with any print function you want
va_end(arg);
if (len >= sizeof(loc_buf)) {
free(temp);
}
return len;
}
Let's say you have a typical variadic function you've written. Because at least one argument is required before the variadic one ..., you have to always write an extra argument in usage.
Or do you?
If you wrap your variadic function in a macro, you need no preceding arg. Consider this example:
#define LOGI(...)
((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
This is obviously far more convenient, since you needn't specify the initial argument every time.
I'm unsure if this works for all compilers, but it has worked so far for me.
void inner_func(int &i)
{
va_list vars;
va_start(vars, i);
int j = va_arg(vars);
va_end(vars); // Generally useless, but should be included.
}
void func(int i, ...)
{
inner_func(i);
}
You can add the ... to inner_func() if you want, but you don't need it. It works because va_start uses the address of the given variable as the start point. In this case, we are giving it a reference to a variable in func(). So it uses that address and reads the variables after that on the stack. The inner_func() function is reading from the stack address of func(). So it only works if both functions use the same stack segment.
The va_start and va_arg macros will generally work if you give them any var as a starting point. So if you want you can pass pointers to other functions and use those too. You can make your own macros easily enough. All the macros do is typecast memory addresses. However making them work for all the compilers and calling conventions is annoying. So it's generally easier to use the ones that come with the compiler.

Resources