This is likely not a good idea to begin with and you'd be much better off using a function + loops in run-time. Especially since you already threw performance out the window by using printf
, so there aren't many arguments for doing all of this at compile-time.
That being said, if you insist on macros and if you can guarantee that the num_symbols
member corresponds to FREQ_MAX_SYMBOL
, you could cook up a clunky, evil list of macros such as these:
#define FREQ_FORMAT_1 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i], cur_freqs: [%i]}"
#define FREQ_FORMAT_2 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i,%i], cur_freqs: [%i,%i]}"
#define FREQ_FORMAT_3 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i,%i,%i], cur_freqs: [%i,%i,%i]}"
#define FREQ_PARAM_1 (f).req_freqs[0], \
(f).cur_freqs[0]
#define FREQ_PARAM_2 (f).req_freqs[0], (f).req_freqs[1], \
(f).cur_freqs[0], (f).cur_freqs[1]
#define FREQ_PARAM_3 (f).req_freqs[0], (f).req_freqs[1], (f).req_freqs[2], \
(f).cur_freqs[0], (f).cur_freqs[1], (f).cur_freqs[2]
You'll need an upper limit for how many arguments you support.
You'd then call these like:
#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)
#define FREQ_FORMAT CONCAT(FREQ_FORMAT_, FREQ_MAX_SYMBOL)
#define FREQ_VALUES(f) (f).num_symbols, (f).tot_freq, CONCAT(FREQ_PARAM_, FREQ_MAX_SYMBOL)
At least the first macro FREQ_FORMAT
requires an extra level of macro expansion since it is an object-like macro and not a function-like macro. Hence we need a helper macro to expand that one. And then the usual problem with ## getting applied before further macro expansion, so that one needs to be in a helper macro of its own.
Full example:
#include <stdio.h>
#define FREQ_MAX_SYMBOL 3
struct freq {
int num_symbols; // <= FREQ_MAX_SYMBOL
int tot_freq; // sum of all the frequencies
int req_freqs[FREQ_MAX_SYMBOL]; // required frequencies
int cur_freqs[FREQ_MAX_SYMBOL]; // current frequencies
};
#define FREQ_FORMAT_1 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i], cur_freqs: [%i]}"
#define FREQ_FORMAT_2 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i,%i], cur_freqs: [%i,%i]}"
#define FREQ_FORMAT_3 "{num_symbols: %i, tot_freq: %i, req_freqs: [%i,%i,%i], cur_freqs: [%i,%i,%i]}"
#define FREQ_PARAM_1 (f).req_freqs[0], \
(f).cur_freqs[0]
#define FREQ_PARAM_2 (f).req_freqs[0], (f).req_freqs[1], \
(f).cur_freqs[0], (f).cur_freqs[1]
#define FREQ_PARAM_3 (f).req_freqs[0], (f).req_freqs[1], (f).req_freqs[2], \
(f).cur_freqs[0], (f).cur_freqs[1], (f).cur_freqs[2]
#define CONCAT_(a,b) a##b
#define CONCAT(a,b) CONCAT_(a,b)
#define FREQ_FORMAT CONCAT(FREQ_FORMAT_, FREQ_MAX_SYMBOL)
#define FREQ_VALUES(f) (f).num_symbols, (f).tot_freq, CONCAT(FREQ_PARAM_, FREQ_MAX_SYMBOL)
int main()
{
struct freq f =
{
.num_symbols = FREQ_MAX_SYMBOL,
.tot_freq = 123,
.req_freqs = {1,2,3},
.cur_freqs = {4,5,6},
};
printf(FREQ_FORMAT, FREQ_VALUES(f));
}
Output:
{num_symbols: 3, tot_freq: 123, req_freqs: [1,2,3], cur_freqs: [4,5,6]}
num_symbols
. You'll need an integer constant expression somewhere or no can do. Is num_symbols guaranteed to be set to FREQ_MAX_SYMBOL somewhere?num_symbols
has a run time value so the answer is no. This is not the job for a macro. Can't you just use a simple function for this?for
loops to print thereq_freqs
andcur_freqs
elements. In multi-threaded applications, you can callflockfile(fp);
/funlockfile(fp);
(for POSIX) or_lock_file(fp);
/_unlock_file(fp);
(for MS Windows) at the start / end of the function to prevent interference from other threads writing to the same stream.