I am searching a nice way to create a "no action" timing (CPU useless operation for timing).
To explain my issue here is the code that I want to change to a macro :
int main (void)
{
int i=0;
printf("Start\r\n");
for(i=0;i<1000;i++); //LINE TO CHANGE TO A MACRO
printf("Delayed trace\r\n");
return 0;
}
Do you have any idea ?
Thanks by advance.
General way for defining such a macro would be:
#define DELAY(amount) \
do { \
/* method of delay */ \
} while (0)
In your case:
#define DELAY(amount) \
do { \
int i; \
for (i = 0; i < amount; ++i); \
} while (0)
If you wish to introduce a delay in terms of some loop iterations, you could employ
#define INTRODUCE_DELAY(count) for(int i = 0; i < count; i++);
You could modify this through a compiler switch to invoke a sleep of similar us as shown below. In case you can't declare i in the for loop then, we can define a small function (which could potentially be inline as shown below
#ifdef WIN32
void mysleep(int count)
{
int i;
for(i = 0; i < count; i++);
}
#define INTRODUCE_DELAY(count) mysleep(count);
#else
#define INTRODUCE_DELAY(count) sleep(count);
#endif
I think you need sleep function, (Work only on unix/linux though)
#include <unistd.h>
#define DELAY(SEC) sleep(SEC)
There must be a similar function in windows.
Related
I want to remove all comments in a toy.c file. From Remove comments from C/C++ code I see that I could use
gcc -E -fpreprocessed -P -dD toy.c
But some of my code (say deprecated functions that I don't want to compile) are wrapped up between #if 0 and endif, as if they were commented out.
One one hand, the above command does not remove this type of "comment" because its removal is only possible during macro expansion, which -fpreprocessed prevents;
On the other hand, I have other macros I don't want to expand, so dropping -fpreprocessed is a bad idea.
I see a dilemma here. Is there a way out of this situation? Thanks.
The following toy example "toy.c" is sufficient to illustrate the problem.
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
gcc -E -fpreprocessed -P -dD toy.c gives
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
while gcc -E -P toy.c gives
int main (void) {
return 3;
}
There's a pair of programs, sunifdef ("Son of unifdef", which is available from unifdef) and coan, that can be used to do what you want. The question Is there a C pre-processor which eliminates #ifdef blocks based on values defined/undefined? has answers which discuss these programs.
For example, given "xyz37.c":
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
#if 0
int main (void) {
printf("%d\n", foo);
}
#endif
Using sunifdef
sunifdef -DDEFINED -ned < xyz37.c
gives
#define foo 3 /* this is a macro */
// a toy function
int main (void) {
return foo;
}
// this is deprecated
and given this file "xyz23.c":
#if 0
This is deleted
#else
This is not deleted
#endif
#if 0
Deleted
#endif
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
#if 1
This is persistent
#else
This is inconsistent
#endif
The program
sunifdef -DDEFINE -ned < xyz23.c
gives
This is not deleted
#if defined(XYZ)
XYZ is defined
#else
XYZ is not defined
#endif
This is persistent
This is, I think, what you're after. The -DDEFINED options seems to be necessary; choose any name that you do not use in your code. You could use -UNEVER_DEFINE_THIS instead, if you prefer. The -ned option evaluates the constant terms and eliminates the relevant code. Without it, the constant terms like 0 and 1 are not eliminated.
I've used sunifdef happily for a number of years (encroaching on a decade). I've not yet found it to make a mistake, and I've used it to clean up some revoltingly abstruse sets of 'ifdeffery'. The program coan is a development of sunifdef with even more capabilities.
The preprocessor doesn't make exceptions. You cannot use it here to do that.
A simple state machine using python can work. It even handles nesting (well, maybe not all cases are covered like nested #if 0 but you can compare the source before & after and manually validate). Also commented code isn't supported (but it seems that you have it covered)
the input (slightly more complex than yours for the demo):
#define foo 3
int main (void) {
return foo;
}
#if 0
int main (void) {
#ifdef DDD
printf("%d\n", foo);
#endif
}
#endif
void other_function()
{}
now the code, using regexes to detect #if & #endif.
import re
rif0 = re.compile("\s*#if\s+0")
rif = re.compile("\s*#(if|ifn?def)")
endif = re.compile("\s*#endif")
if_nesting = 0
if0_nesting = 0
suppress = False
with open("input.c") as fin, open("output.c","w") as fout:
for l in fin:
if rif.match(l):
if_nesting += 1
if rif0.match(l):
suppress = True
if0_nesting = if_nesting
elif endif.match(l):
if if0_nesting == if_nesting:
suppress = False
if_nesting -= 1
continue # don't write the #endif
if not suppress:
fout.write(l))
the output file contains:
#define foo 3
int main (void) {
return foo;
}
void other_function()
{}
so the nesting worked and the #if 0 part was successfully removed. Not something that sed "/#if 0/,/#endif/d can achieve.
Thanks for the other two answers.
I am now aware of unifdef and sunifdef. I am happy to know the existence of these tools, and that I am not the only one who wants to do this kind of code cleaning.
I have also written a rm_if0_endif.c (attached below) for removing an #if 0 ... #endif block which is sufficient for me. Its philosophy is based on text processing. It scans an input C script, locating #if 0 and the correct enclosing endif, so that this block can be omitted during char-to-char copying.
The text processing approach is limited, as it is designed for #if 0 ... #endif case only, but is all I need for now. A C program is not the only way for this kind of text processing. Jean-François Fabre's answer demonstrates how to do it in Python. I can also do something similar in R, using readLines, startsWith and writeLines. I chose to do it in C as I am not yet an expert in C so this task drives me to learn. Here is a demo of my rm_if0_endif.c. Note that the program can concatenate several C files and add header for each file.
original input file input.c
#define foo 3 /* this is a macro */
// a toy function
int test1 (void) {
return foo;
}
#if 0
#undef foo
#define foo 4
#ifdef bar
#warning "??"
#endif
// this is deprecated
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
// another toy
int test2 (void) {
return foo;
}
gcc pre-processing output "gcc_output.c" (taken as input for my program)
gcc -E -fpreprocessed -P -dD input.c > gcc_output.c
#define foo 3
int test1 (void) {
return foo;
}
#if 0
#undef foo
#define foo 4
#ifdef bar
#warning "??"
#endif
int main (void) {
printf("%d\n", foo);
return 0;
}
#endif
int test2 (void) {
return foo;
}
final output final_output.c from my program
rm_if0_endif.c has a utility function pattern_matching and a workhorse function rm_if0_endif:
void rm_if0_endif (char *InputFile,
char *OutputFile, char *WriteMode, char *OutputHeader);
The attached file below has a main function, doing
rm_if0_endif("gcc_output.c",
"final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");
It produces:
// this is a demo of 'rm_if0_endif.c'
#define foo 3
int test1 (void) {
return foo;
}
int test2 (void) {
return foo;
}
Appendix: rm_if0_endif.c
#include <stdio.h>
int pattern_matching (FILE *fp, const char *pattern, int length_pattern) {
int flag = 1;
int i, c;
for (i = 0; i < length_pattern; i++) {
c = fgetc(fp);
if (c != pattern[i]) {
flag = 0; break;
}
}
return flag;
}
void rm_if0_endif (char *InputFile,
char *OutputFile, char *WriteMode, char *OutputHeader) {
FILE *fp_r = fopen(InputFile, "r");
FILE *fp_w = fopen(OutputFile, WriteMode);
fpos_t pos;
if (fp_r == NULL) perror("error when opening input file!");
fputs(OutputHeader, fp_w);
int c, i, a1, a2;
int if_0_flag, if_flag, endif_flag, EOF_flag;
const char *if_0 = "if 0";
const char *endif = "endif";
EOF_flag = 0;
while (EOF_flag == 0) {
do {
c = fgetc(fp_r);
while ((c != '#') && (c != EOF)) {
fputc(c, fp_w);
c = fgetc(fp_r);
}
if (c == EOF) {
EOF_flag = 1; break;
}
fgetpos(fp_r, &pos);
if_0_flag = pattern_matching(fp_r, if_0, 4);
fsetpos(fp_r, &pos);
if (if_0_flag == 0) fputc('#', fp_w);
} while (if_0_flag == 0);
if (EOF_flag == 1) break;
a1 = 1; a2 = 0;
do {
c = fgetc(fp_r);
while (c != '#') c = fgetc(fp_r);
fgetpos(fp_r, &pos);
if_flag = pattern_matching(fp_r, if_0, 2);
fsetpos(fp_r, &pos);
if (if_flag == 1) a1++;
fgetpos(fp_r, &pos);
endif_flag = pattern_matching(fp_r, endif, 5);
fsetpos(fp_r, &pos);
if (endif_flag == 1) a2++;
} while (a1 != a2);
for (i = 0; i < 5; i++) c = fgetc(fp_r);
if (c == EOF) {
EOF_flag == 1;
}
}
fclose(fp_r);
fclose(fp_w);
}
int main (void) {
rm_if0_endif("gcc_output.c",
"final_output.c", "w", "// this is a demo of 'rm_if0_endif.c'\n");
return 0;
}
I made this state machine :
enum states { STATE_ENTRY, STATE_....} current_state;
enum events { EVENT_OK, EVENT_FAIL,EVENT_REPEAT, MAX_EVENTS } event;
void (*const state_table [MAX_STATES][MAX_EVENTS]) (void) = {
{ action_entry , action_entry_fail , action_entry_repeat }, /*
procedures for state 1 */
......}
void main (void){
event = get_new_event (); /* get the next event to process */
if (((event >= 0) && (event < MAX_EVENTS))
&& ((current_state >= 0) && (current_state < MAX_STATES))) {
state_table [current_state][event] (); /* call the action procedure */
printf("OK 0");
} else {
/* invalid event/state - handle appropriately */
}
}
When I modify a global variable in one state the global variable remain the same , and I need that variable in all the states . Do you now what could be the problem ?
My Global variable is this structure:
#if (CPU_TYPE == CPU_TYPE_32)
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[64];
} BigNumber;
#elif (CPU_TYPE == CPU_TYPE_16)
typedef uint16_t word;
#define word_length 16
typedef struct BigNumber {
word words[128];
} BigNumber;
#else
#error Unsupported CPU_TYPE
#endif
BigNumber number1 , number2;
Here is how I modify:
//iterator is a number from where I start to modify,
//I already modified on the same way up to the iterator
for(i=iterator+1;i<32;i++){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
This is just in case you may want to change your approach for defining the FSM. I'll show you with an example; say you have the following FSM:
You may represent it as:
void function process() {
fsm {
fsmSTATE(S) {
/* do your entry actions heare */
event = getevent();
/* do you actions here */
if (event.char == 'a') fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(A) {
event = getevent();
if (event.char == 'b' || event.char == 'B') fsmGOTO(B);
else fsmGOTO(E);
}
fsmSTATE(B) {
event = getevent();
if (event.char == 'a' ) fsmGOTO(A);
else fsmGOTO(E);
}
fsmSTATE(E) {
/* done with the FSM. Bye bye! */
}
}
}
I do claim (but I believe someone will disagree) that this is simpler, much more readable and directly conveys the structure of the FSM than using a table. Even if I didn't put the image, drawing the FSM diagram would be rather easy.
To get this you just have to define the fsmXXX stuff as follows:
#define fsm
#define fsmGOTO(x) goto fsm_state_##x
#define fsmSTATE(x) fsm_state_##x :
Regarding the code that changese number2:
for(i=iterator+1;i<32;i){
nr_rand1=661;
nr_rand2=1601;
nr_rand3=1873;
number2.words[i]=(nr_rand1<<21) | (nr_rand2<<11) | (nr_rand3);
}
I can't fail to note that:
i is never incremented, so just one element of the array is changed (iterator+1) over an infinite loop;
even if i would be incremented, only the a portion of the words array it's changed depending on the value of iterator (but this might be the intended behaviour).
unless iterator can be -1, the element words[0] is never changed (again this could be the intended behaviour).
I would check if this is really what you intended to do.
If you're sure that it's just a visibility problem (since you said that when you declare it as local it worked as expected), the only other thing that I can think of is that you have the functions in one file and the main (or where you do your checks) in another.
Then you include the same .h header in both files and you end up (due to the linker you're using) with two different number2 because you did not declare it as extern in one of the two files.
Your compiler (or, better, the linker) should have (at least) warned you about this, did you check the compilation messages?
This is not an answer - rather it is a comment. But it is too big to fit the comment field so I post it here for now.
The code posted in the question is not sufficient to find the root cause. You need to post a minimal but complete example that shows the problem.
Something like:
#include<stdio.h>
#include<stdlib.h>
#include <stdint.h>
typedef uint32_t word;
#define word_length 32
typedef struct BigNumber {
word words[4];
} BigNumber;
BigNumber number2;
enum states { STATE_0, STATE_1} current_state;
enum events { EVENT_A, EVENT_B } event;
void f1(void)
{
int i;
current_state = STATE_1;
for (i=0; i<4; ++i) number2.words[i] = i;
}
void f2(void)
{
int i;
current_state = STATE_0;
for (i=0; i<4; ++i) number2.words[i] = 42 + i*i;
}
void (*const state_table [2][2]) (void) =
{
{ f1 , f1 },
{ f2 , f2 }
};
int main (void){
current_state = STATE_0;
event = EVENT_A;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
event = EVENT_B;
state_table [current_state][event] (); /* call the action procedure */
printf("%u %u %u %u\n", number2.words[0], number2.words[1], number2.words[2], number2.words[3]);
return 0;
}
The above can be considered minimal and complete. Now update this code with a few of your own functions and post that as the question (if it still fails).
My code doesn't fail.
Output:
0 1 2 3
42 43 46 51
In the following code there is a calling convention error(possibly leading to an eternal loop), and i cannot detect it. I try to verify the code using 'Satabs'. What kind of model can bring the error to the surface. With the following model i get a segfault.
By changing the VLEN and TMAX you can play a bit.
Q1. What is the calling convention error?
Q2. What kind of model would be most appropriate to use for finding the error?
#include <stdio.h>
#if MODEL==1
#define VLEN 3
#define TMAX 4
int trans(int T,int*src,int*dst){
if (T < VLEN && T < TMAX && src[T] < 4){
dst[T]=src[T]+1;
return 1;
} else {
return 0;
}
}
#endif
struct next_state {
int next;
int src[VLEN];
};
typedef struct next_state *iterator_t;
void init(iterator_t iter,int *src){
for(int i=0;i<VLEN;i++){
iter->src[i]=src[i];
}
iter->next=0;
}
int next(iterator_t iter,int *dst){
#ifdef FIX_ARRAY
for(int i=0;i<VLEN;i++){
#else
for(int i=0;i<TMAX;i++){
#endif
dst[i]=iter->src[i];
}
int res=0;
while(!res&&iter->next<TMAX){
res=trans(iter->next,iter->src,dst);
iter->next++;
}
return res;
}
int find_depth(iterator_t iter,int *src){
int table[VLEN*TMAX];
int N=0;
init(iter,src);
for(int i=0;i<TMAX;i++){
if(next(iter,&(table[N*VLEN]))){
N++;
}
}
int depth=0;
for(int i=0; i<N;i++){
printf("Eimai stin for \n");
int tmp=find_depth(iter,&(table[i*VLEN]));
printf("tmp= %d\n",tmp);
if(tmp>=depth){
depth=tmp+1;
//assert(depth);
}
}
printf("\n\n");
return depth;
}
int main(int argc,char*argv[]){
int state[VLEN];
struct next_state ns;
for(int i=0;i<VLEN;i++){
state[i]=0;
}
int depth=find_depth(&ns,state);
printf("depth is %d\n",depth);
}
int depth=find_depth(&ns,state);
You are passing &ns, but taking arg in function as iterator_t iter, is this correct ?
void init(iterator_t iter,int *src){
for(int i=0;i<VLEN;i++){
iter->src[i]=src[i];
iter->src[i] is this expression fine?
I dont know 'Satabs' but the most promising candidate for an endless loop for me seems to be
while(!res&&iter->next<TMAX){
res=trans(iter->next,iter->src,dst);
iter->next++;
}
All other loops rather look like fix count.
This loop might be dangerous for itself even without the so called calling convention error, which doest jump to my eye yet.
Anyhow you should take a look not only to the call of the funtion trans but the whole call tree to it.
You could also try to paste your code there
http://gimpel-online.com//cgi-bin/genPage.py?srcFile=intro.txt&cgiScript=analyseCode.py&title=Introduction+and+Welcome&intro=Introducing+the+testing+facility&compilerOption=online32.lnt&in
Maybe you get a few more hints.
Just a guess:
Maybe 'Satabs' doesn't like undefined preprocessor conditions
like
#if MODEL==1
I have the following macros that take a statement and multiply it
#define X2(s) do { s; s; } while (0)
#define X3(s) do { s; s; s; } while (0)
#define X4(s) do { s; s; s; s; } while (0)
#define X5(s) do { s; s; s; s; s; } while (0)
#define X6(s) do { s; s; s; s; s; s; } while (0)
etc.
so the pre-processor expands
X2(i++)
to
do { i++; i++; } while (0)
I would like to have a macro
#define CODE_MULTIPLIER(x,s)
which expands a statement s, x times. so
CODE_MULTIPLIER(3,j--)
would be expanded to
do { j--; j--; j--; } while (0)
The ugly idea i came up with is:
#define CODE_MULTIPLIER(x,s) do { \
if ((x) == 1) { s; } \
else if ((x) == 2) { s; s; } \
else if ((x) == 3) { s; s; s; } \
else if ((x) == 4) { s; s; s; s; } \
else if ((x) == 5) { s; s; s; s; s; } \
etc. \
else assert(0); \
} while (0)
hoping the compiler will optimize out the ifs
Why would you ever want macros like this?
One reason (but not the only one) is the need for exact delays in embedded programming. using while/for loops slightly change the timing. Compiler optimization of loops may not preserve delicate timing requirements.
Here is a typical usage example:
#define CLOCK_FREQ_Hz (16000000L)
#define US_TO_NOPS(us) ((us) * CLOCK_FREQ_Hz / 1000000L)
#define OFF_ON_DELAY_US (4) // units: microseconds
#define ON_OFF_DELAY_US (2) // units: microseconds
#define OFF_ON_DELAY_NOPS US_TO_NOPS(OFF_ON_DELAY_US) // units: instructions
#define ON_OFF_DELAY_NOPS US_TO_NOPS(ON_OFF_DELAY_US) // units: instructions
PIN = OFF;
CODE_MULTIPLIER(OFF_ON_DELAY_NOPS,asm("nop")); // 4us delay
PIN = ON;
CODE_MULTIPLIER(ON_OFF_DELAY_NOPS,asm("nop")); // 2us delay
PIN = OFF;
I would appreciate any suggestions as to how to create this macro. High preference to compiler-independent macro wizardry (Us embedded dudes don't always have the luxury of using GCC)
Thanx
Yes such things are possible if you don't stretch things too much. P99 has a whole series of macros to accomplish different sorts of such unrolling. An easy one here would be
#define toto(I) f(I)
P99_UNROLL(toto, 3); // => f(0); f(1); f(2);
But beware that for using P99 you'd need a compiler that implements C99 compliant preprocessor.
As recursion cannot be generally used in macros, and you may not have "extended unrolling features" the only way to have a "always valid solution" is to do some manual work like following one:
#define X1(s) do { s;} while (0)
#define X2(s) do { s; s; } while (0)
#define X3(s) do { s; s; s; } while (0)
#define X4(s) do { s; s; s; s; } while (0)
#define X5(s) do { s; s; s; s; s; } while (0)
#define X6(s) do { s; s; s; s; s; s; } while (0)
#define CODE_MULTIPLIER(s, i) X##i(s)
And you just use CODE_MULTIPLIER(s, i) in your code. In this way you avoid the if/else if conditional expressions. For example you will use CODE_MULTIPLIER(i++,3).
Another trick can be applied if you aren't going to use X1,X2.... but only CODE_MULTIPLIER(s,i):
#define X1(s) s
#define X2(s) s; X1(s)
#define X3(s) s; X2(s)
#define X4(s) s; X3(s)
#define X5(s) s; X4(s)
#define X6(s) s; X5(s)
#define CODE_MULTIPLIER(s, i) do { X##i(s); } while (0)
which has a nicer sintax.
Does someone know of any C99 preprocessor magic that allows for creating a string consisting of another string repeated N times?
E.g.
STRREP( "%s ", 3 )
becomes
"%s %s %s "
after preprocessing.
The only thing I could think of myself was something like this
#define STRREP( str, N ) STRREP_##N( str )
#define STRREP_0(str) ""
#define STRREP_1(str) str
#define STRREP_2(str) str str
#define STRREP_3(str) str str str
...
which works well, but is ugly as I have to define a macro for each repetition length manually. I want to use it together with variadic macros and the macro returning the number of macro arguments shown here.
Since it's a macro and N is a numeric constant anyway, how about this?
#include <stdio.h>
#define REP0(X)
#define REP1(X) X
#define REP2(X) REP1(X) X
#define REP3(X) REP2(X) X
#define REP4(X) REP3(X) X
#define REP5(X) REP4(X) X
#define REP6(X) REP5(X) X
#define REP7(X) REP6(X) X
#define REP8(X) REP7(X) X
#define REP9(X) REP8(X) X
#define REP10(X) REP9(X) X
#define REP(HUNDREDS,TENS,ONES,X) \
REP##HUNDREDS(REP10(REP10(X))) \
REP##TENS(REP10(X)) \
REP##ONES(X)
int main(void)
{
printf(REP(9,0,7, "*")); // "*" repeated 907 times
printf(REP(0,9,2, "#")); // "#" repeated 92 times
printf(REP(0,0,1, "#")); // "#" repeated 1 times
return 0;
}
My suggestion is to use the boost.
E.g.
#include <stdio.h>
#include <boost/preprocessor/repetition/repeat.hpp>
#define Fold(z, n, text) text
#define STRREP(str, n) BOOST_PP_REPEAT(n, Fold, str)
int main(){
printf("%s\n", STRREP("%s ", 3));//STRREP("%s ", 3) -> "%s %s %s "
return 0;
}
I recently discovered a recursion scheme with the CPP c-preprocessor file inclusion mechanism over the __INCLUDE_LEVEL__ preprocessor literal which is treated automatically - so maybe this algorithm only works for gcc ?!?
The algorithm is conceptually unlimited, it can be extended with additional file indirection.
The herin presented code handles an ITERATION_COUNT from 0-39202
With the comment/uncomment of the ITERATION_SEPARATOR you can
generate N elements, or 1 element with N concatenations, suitable for string repetitions.
The ITERATION_ELEMENT macro is used as the "repetition element"
You can compile the code regulary, without any additional defines. The macro invocation inside the code is idempotent.
An exemplary output:
> gcc iterate.c -o iterate -Wall -s -O3 && ./iterate.exe
0-1591 Counter
1592 Elements
iterate.c:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
const char * preproc_array[] = {
#define ITERATION_COUNT 1592 //0-(199*197-1)39202 (maximum counter)
#define ITERATION_SEPARATOR , //this macro, if active, determines wheather there exits N separate elements otherwise, if outcommented, just 1 element with N concatenations
#define ITERATION_ELEMENT 0-__COUNTER__ Counter\n //the expanded macro as an arbitrary element
#include "iterate.h"
};
return !printf("%s%"PRIu32" Elements",preproc_array[
#ifndef NO_ITERATION_SEPARATOR
__COUNTER__-1
#else
0
#endif
], sizeof(preproc_array)/sizeof(const char *));
}
iterate.h:
#define ITERATION_START 1 //start index of first inclusion
#define ITERATION_LIMIT 199 //conforming to CPP preprocessor manual pg. 54 chapter 11.5, a limit of 200 is set arbitrary
#define ITERATION(...) _ITERATION(__VA_ARGS__)
#define _ITERATION(...) #__VA_ARGS__ ITERATION_SEPARATOR
#ifndef ITERATION_SEPARATOR
#define ITERATION_SEPARATOR
#define NO_ITERATION_SEPARATOR
#endif
//here begins the recursive algorithm via preprocessor file inclusion, enable the warnings if you want to see how it loops through
#if __INCLUDE_LEVEL__ <= ITERATION_COUNT/ITERATION_LIMIT
//~ #warning DIV
#define ITERATION_END ITERATION_COUNT/ITERATION_LIMIT+3 // + offset
#include "loop.h"
#define ITERATION_END ITERATION_LIMIT
#include "loop.h"
#include "iterate.h"
#endif
#if __INCLUDE_LEVEL__ == ITERATION_START
//~ #warning MOD
#define ITERATION_END ITERATION_COUNT%ITERATION_LIMIT+ITERATION_START
#include "loop.h"
#if ITERATION_COUNT % ITERATION_LIMIT
#define ITERATION_END 3 // + offset
#include "loop.h"
#endif
#endif
//end of alogrithm
loop.h:
#if __INCLUDE_LEVEL__ < ITERATION_END
#include "loop.h"
ITERATION(ITERATION_ELEMENT)
#undef ITERATION_END
#endif
Not sure whether it can be done with the macro but you can do it with the function like:
char *strrep(const char *str, int nrep)
{
if (nrep <= 0 || !str) return NULL;
char *buf = malloc(strlen(str) * nrep + 1);
if (!buf) return NULL;
for (int i = 0; i < nrep; ++i) {
strcat(buf, str);
}
return buf;
}
Now you can use it:
char *r = strrep("%s", 3);
if (r) {
...
free(r);
}
UPD: If you want to avoid malloc/free this is a variant of the first code:
/* .h */
#define STRREP_MAX_CHARS 1024
#define STRREP_INIT static char __strrep_buffer[STRREP_MAX_CHARS]
#define STRREP(str, nrep) strrep(str, nrep) ? __strrep_buffer : ""
char *strrep(const char *str, int nrep);
/* .c */
STRREP_INIT;
char *strrep(const char *str, int nrep)
{
if (nrep <= 0 || !str) return 0;
if (strlen(str) * nrep >= STRREP_MAX_CHARS) return 0;
memset(__strrep_buffer, 0, STRREP_MAX_CHARS);
for (int i = 0; i < nrep; ++i) {
strcat(__strrep_buffer, str);
}
return __strrep_buffer;
}
Now:
printf("%s\n", STRREP("%s", 3));
OTOH, this looks even uglier than the first one.
How about something like this?
#define DUP2(str) str str
#define DUP4(str) DUP2(str) DUP2(str)
#define DUP8(str) DUP4(str) DUP4(str)
#define DUP16(str) DUP8(str) DUP8(str)
#define DUP32(str) DUP16(str) DUP16(str)
#define DUP64(str) DUP32(str) DUP32(str)
#define DUP128(str) DUP64(str) DUP64(str)
#define DUP256(str) DUP128(str) DUP128(str)
#define DUP512(str) DUP256(str) DUP256(str)
#define DUP1024(str) DUP512(str) DUP512(str)