Aargh! Why is the compiler complaining? Thanks for any help!
% gcc -o mine mine.c -lcrypt
mine.c: In function 'main':
mine.c:19:14: warning: assignment makes pointer from integer without a cast [enabled by default]
%
Code:
#define _X_OPEN_SOURCE
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main() {
const char key[] = "hello world";
const char salt[]="01";
const int MAXIMUM_HASH_LENGTH = 2 + 11;
int i=0;
char *hash;
long long hashes = 0L;
while (1) {
hash = crypt(key, salt); /* problem with this line... */
if (hash[2] == '0') {
int leading0s = 0;
leading0s++;
for (i=3; i < MAXIMUM_HASH_LENGTH; i++) {
if (hash[i] != '0') break;
leading0s++;
}
printf("Winner: %s has %d leading zeros.\n",
hash, leading0s);
printf("\t--> Hash %lld.\n\n", hashes);
}
if (hashes != 0 && (hashes % 10000) == 0) {
printf("Hash %d: %s\n", hashes, hash);
}
if (hashes== 1000000) break;
hashes++;
}
return 1000;
}
Try changing "#define _X_OPEN_SOURCE" to "#define _XOPEN_SOURCE".
You should normally specify a number for _XOPEN_SOURCE; valid values include:
/*
** Include this file before including system headers. By default, with
** C99 support from the compiler, it requests POSIX 2001 support. With
** C89 support only, it requests POSIX 1997 support. Override the
** default behaviour by setting either _XOPEN_SOURCE or _POSIX_C_SOURCE.
*/
/* _XOPEN_SOURCE 700 is loosely equivalent to _POSIX_C_SOURCE 200809L */
/* _XOPEN_SOURCE 600 is loosely equivalent to _POSIX_C_SOURCE 200112L */
/* _XOPEN_SOURCE 500 is loosely equivalent to _POSIX_C_SOURCE 199506L */
#if !defined(_XOPEN_SOURCE) && !defined(_POSIX_C_SOURCE)
#if __STDC_VERSION__ >= 199901L
#define _XOPEN_SOURCE 600 /* SUS v3, POSIX 1003.1 2004 (POSIX 2001 + Corrigenda) */
#else
#define _XOPEN_SOURCE 500 /* SUS v2, POSIX 1003.1 1997 */
#endif /* __STDC_VERSION__ */
#endif /* !_XOPEN_SOURCE && !_POSIX_C_SOURCE */
You may prefer to use 700 instead of 600; it depends on your platform(s). However, with the correct spelling, you can simply write #define _XOPEN_SOURCE and it will also define the crypt() for you.
You might also care to note that the exit status is limited to an 8-bit value, so returning 1000 from main() is equivalent to returning 1000 % 256. You also need to fix line 34 of your code:
printf("Hash %d: %s\n", hashes, hash);
should be:
printf("Hash %lld: %s\n", hashes, hash);
Related
tmp2.c
/*
gcc -Wall -Werror -g assert.c tmp2.c && ./a.out
*/
#include "tmp2.h"
#include <assert.h>
int main(void)
{
// assert(1 == 2);
Assert(1 == 2);
return 0;
}
tmp2.h
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include <math.h>
#include<stdint.h>
#include<stdalign.h>
#include<stdbool.h>
/*
* BoolIsValid
* True iff bool is valid.
*/
#define BoolIsValid(boolean) ((boolean) == false || (boolean) == true)
/*
* PointerIsValid
* True iff pointer is valid.
*/
#define PointerIsValid(pointer) ((const void*)(pointer) != NULL)
extern void
ExceptionalCondition(const char *conditionName,
const char *fileName,
int lineNumber);
/*
* USE_ASSERT_CHECKING, if defined, turns on all the assertions.
* - plai 9/5/90
*
* It should _NOT_ be defined in releases or in benchmark copies
*/
/*
* Assert() can be used in both frontend and backend code. In frontend code it
* just calls the standard assert, if it's available. If use of assertions is
* not configured, it does nothing.
*/
#define USE_ASSERT_CHECKING 0
#ifndef USE_ASSERT_CHECKING
#define Assert(condition) ((void)true)
#define AssertMarcod(condition) ((void)true)
#elif defined(FRONTEND)
#include<assert.h>
#define Assert(p) assert(p)
#define AssertMarco(p) ((void) assert(p))
#else
/*
* Assert
* Generates a fatal exception if the given condition is false.
*/
#define Assert(condition) \
do { \
if (!(condition)) \
ExceptionalCondition(#condition,__FILE__,__LINE__); \
} while (0)
/*
* AssertMacro is the same as Assert but it's suitable for use in
* expression-like macros, for example:
*
* #define foo(x) (AssertMacro(x != 0), bar(x))
*/
#define AssertMacro(condition) \
((void) ((condition) || \
(ExceptionalCondition(#condition,__FILE__,__LINE__),0)))
#endif
assert.c
#include "tmp2.h"
#include <unistd.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
#endif
/*
* ExceptionalCondition - Handles the failure of an Assert()
*
* We intentionally do not go through elog() here, on the grounds of
* wanting to minimize the amount of infrastructure that has to be
* working to report an assertion failure.
*/
void
ExceptionalCondition(const char *conditionName,
const char *fileName,
int lineNumber)
{
/* Report the failure on stderr (or local equivalent) */
if (!PointerIsValid(conditionName)
|| !PointerIsValid(fileName))
fprintf(stderr,"TRAP: ExceptionalCondition: bad arguments in PID %d\n",
(int) getpid());
else
fprintf(stderr,"TRAP: failed Assert(\"%s\"), File: \"%s\", Line: %d, PID: %d\n",
conditionName, fileName, lineNumber, (int) getpid());
/* Usually this shouldn't be needed, but make sure the msg went out */
fflush(stderr);
// /* If we have support for it, dump a simple backtrace */
// #ifdef HAVE_BACKTRACE_SYMBOLS
// {
// void *buf[100];
// int nframes;
// nframes = backtrace(buf, lengthof(buf));
// backtrace_symbols_fd(buf, nframes, fileno(stderr));
// }
// #endif
/*
* If configured to do so, sleep indefinitely to allow user to attach a
* debugger. It would be nice to use pg_usleep() here, but that can sleep
* at most 2G usec or ~33 minutes, which seems too short.
*/
#ifdef SLEEP_ON_ASSERT
sleep(1000000);
#endif
abort();
}
In this context, I'm trying a way to use the AssertMacro; that is, find a way to invoke assert.c ExceptionalCondition function. Assume FRONTEND is not defined. USE_ASSERT_CHECKING can be 1 or 0.
update: to use ExceptionalCondition function I need to declare it on tmp2.h via
extern void
ExceptionalCondition(const char *conditionName,
const char *fileName,
int lineNumber);
I also need to define USE_ASSERT_CHECKING in tmp2.h or before tmp2.h.
If I don't define USE_ASSERT_CHECKING seems all the assert will be true always?
About compile suricata.
In Makefile,when CFLAGS wrap "-Werror-implicit-function-declaration"
I got the error:
detect-engine-siggroup.c: In function ‘SigGroupHeadFree’:
detect-engine-siggroup.c:187:9: error: implicit declaration of function ‘_mm_free’ [-Werror=implicit-function-declaration]
SCFreeAligned(sgh->mask_array);
^
detect-engine-siggroup.c: In function ‘SigGroupHeadBuildHeadArray’:
detect-engine-siggroup.c:1715:5: error: implicit declaration of function ‘_mm_malloc’ [-Werror=implicit-function-declaration]
sgh->mask_array = (SignatureMask *)SCMallocAligned((cnt * sizeof(SignatureMask)), 16);
When I delete "-Werror-implicit-function-declaration" in Makefile,I will got the error:
detect-engine-siggroup.o: In function `SigGroupHeadFree':
/root/suricata/suricata-2.0.9/src/detect-engine-siggroup.c:187: undefined reference to `_mm_free'
detect-engine-siggroup.o: In function `SigGroupHeadBuildHeadArray':
/root/suricata/suricata-2.0.9/src/detect-engine-siggroup.c:1715: undefined reference to `_mm_malloc'
Note:_mm_free and _mm_malloc is define in util-mem.h
Yet,I add some code in the other source file,but not in detect-engine-siggroup.c and util-mem.h.
What's wrong?
in detect-engine-siggroup.c(note I have deleted some redundant code here):
void SigGroupHeadFree(SigGroupHead *sgh)
{
if (sgh == NULL)
return;
SCLogDebug("sgh %p", sgh);
PatternMatchDestroyGroup(sgh);
#if defined(__SSE3__) || defined(__tile__)
if (sgh->mask_array != NULL) {
/* mask is aligned */
SCFreeAligned(sgh->mask_array);
sgh->mask_array = NULL;
}
#endif
if (sgh->head_array != NULL) {
SCFree(sgh->head_array);
sgh->head_array = NULL;
}
if (sgh->match_array != NULL) {
detect_siggroup_matcharray_free_cnt++;
detect_siggroup_matcharray_memory -= (sgh->sig_cnt * sizeof(Signature *));
SCFree(sgh->match_array);
sgh->match_array = NULL;
}
sgh->sig_cnt = 0;
if (sgh->init != NULL) {
SigGroupHeadInitDataFree(sgh->init);
sgh->init = NULL;
}
SCFree(sgh);
detect_siggroup_head_free_cnt++;
detect_siggroup_head_memory -= sizeof(SigGroupHead);
return;
}
in util-mem.h(note I have deleted some redundant code here):
#ifndef __UTIL_MEM_H__
#define __UTIL_MEM_H__
#include "util-atomic.h"
#if CPPCHECK==1
#define SCMalloc malloc
#define SCCalloc calloc
#define SCRealloc realloc
#define SCFree free
#define SCStrdup strdup
#define SCMallocAligned _mm_malloc
#define SCFreeAligned _mm_free
#else /* CPPCHECK */
#if defined(_WIN32) || defined(__WIN32)
#include "mm_malloc.h"
#endif
#if defined(__tile__)
/* Need to define __mm_ function alternatives, since these are SSE only.
*/
#include <malloc.h>
#define _mm_malloc(a,b) memalign((b),(a))
#define _mm_free(a) free((a))
#endif /* defined(__tile__) */
SC_ATOMIC_EXTERN(unsigned int, engine_stage);
/* Use this only if you want to debug memory allocation and free()
* It will log a lot of lines more, so think that is a performance killer */
/* Uncomment this if you want to print memory allocations and free's() */
//#define DBG_MEM_ALLOC
#ifdef DBG_MEM_ALLOC
#define SCFree(a) ({ \
extern uint8_t print_mem_flag; \
if (print_mem_flag == 1) { \
SCLogInfo("SCFree at %p", (a)); \
} \
free((a)); \
})
#else /* !DBG_MEM_ALLOC */
#define SCFree(a) ({ \
free(a); \
})
#if defined(__WIN32) || defined(_WIN32)
#define SCFreeAligned(a) ({ \
_mm_free(a); \
})
#else /* !win */
#define SCFreeAligned(a) ({ \
_mm_free((a)); \
})
#endif /* __WIN32 */
#endif /* DBG_MEM_ALLOC */
#endif /* CPPCHECK */
#endif /* __UTIL_MEM_H__ */
#endif /* DBG_MEM_ALLOC */
#endif /* CPPCHECK */
#endif /* __UTIL_MEM_H__ */
/*********************************************************************/
Now solved the problem,reason is forgetting to #include <pmmintrin.h> /* for SSE3 */
/*********************************************************************/
It looks like you have not included util-mem.h properly. SCFreeAligned seem to expand to _mm_free, but _mm_free doesn't seem to expand. Looking at the header file the definition of _mm_free seem to be dependent on __title__ being defined.
Then the compiler just sees a call to _mm_free which is given an implicit prototype as _mm_free doesn't exist. Then of course _mm_free will not be found during linking.
I am new to C have come across a problem that I think some of you may have had in the past. I am trying to code a program that has the user input a bunch of grades and the program tells you how many A,B,C,D,Fs you have entered.
How ever, the problem is that my counter for the grades just wont work.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include<stdint.h>
//MACRO
#define F_Range (0-49)
#define D_Range (50-59)
#define C_Range (60-69)
#define B_Range (70-79)
#define A_Range (80-100)
#define A_COUNTer
#define B_COUNTer
#define C_COUNter
#define D_COUNTer
#define F_COUNTer
//Function Prototype
void display(void);
int main(int argc, char** argv) {
{
float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter;
printf("Total Number of grades 'A' (80-100) = %.2f",A_Counter);
//the rest of the displays would go here
do
{
fflush (stdin);
scanf("%f",&input); //Get input from user
if (input == F_Range);
{
F_Counter++;
}
if (input == D_Range);
{
D_Counter++;
}
if (input == C_Range);
{
C_Counter++;
}
if (input == B_Range);
{
B_Counter++;
}
if (input == A_Range);
{
A_Counter++;
}
}
while (input != 999);
//Exit
{
}
return 0;
}
}
ok so for start when using #define x y you simply say "change all the reference to 'x' with 'y'" so when you have
#define C_Range (60-69)
and then
if (input == C_Range );
it iterputes as
if (input == (60-69));
which makes no sense, plus you have the ";" at the end of the if statement which doesn't make sense either
instead use:
#define F_RangeLow 0
#define F_RangeHigh 49
and the if statement
if (input >= F_RangeLow && input <= F_RangeHigh )
now another thing you have to do is to initiate the counter with 0. that's because you want to stat counting from 0...
float F_Counter=0;
there is no need for 2 "{" at the start of the main
this is quite enough:
int main(int argc, char** argv) {
.
.
.
}
Your counter variables are uninitialized. So, they hold unknown values. So you have to change float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter; to float input, F_Counter=0, D_Counter=0, C_Counter=0, B_Counter=0, A_Counter=0;
Your code has multiple major issues.
The first is that your Range macros don't expand to working code:
#define F_Range (0-49)
…
if (input == F_Range);
This expands to:
if (input == (0-49));
which is only true if input is -49. If you want to check if input is between 0 and 49, you'll have to do that explicitly:
if (input >= 0 && input <= 49)
Given your current level of understanding of C, it's probably best if you don't use macros for now. Leave them alone, write out code in full, and start using macros once you have a firm grasp of the language.
The following line:
printf("Total Number of grades 'A' (80-100) = %.2f",""A_Counter);
^^
has a stray pair of quotation marks. (Does this even compile?)
Additionally:
You've got a semicolon at the end of the if statement mentioned above, which makes it not work correctly.
Your counter variables are not initialized to zero.
float input, F_Counter, D_Counter, C_Counter, B_Counter, A_Counter;
In the main() context you are incrementing these values and none of them are initialized. You have undefined behavior when you have uninitialized vairables.
The values should be initialized like
float input =0,F_Counter=0;/* similarly for the rest */
Checking the range using the macros also needs to be fixed (0-49) doesn't mean you are checking the range from 0 to 49 . Comparison operators should be used in these cases.
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <stdint.h>
#define S_(x) #x
#define S(x) S_(x)
#define RANGE_S(x) S((x##_Range))
#define COUNTER(x) x##_Counter
#define DISP(x) \
printf("Total Number of grades '%c' %s = %d\n",\
CHAR(x), RANGE_S(x), COUNTER(x))
#define CHECK(var, x) atoi(S(x##_Range)) <= var
#define CHAR(x) *#x
#define F_Range 0-49
#define D_Range 50-59
#define C_Range 60-69
#define B_Range 70-79
#define A_Range 80-100
void display(void);
int main(int argc, char** argv) {
float input;
int COUNTER(A)=0, COUNTER(B)=0, COUNTER(C)=0, COUNTER(D)=0, COUNTER(F)=0;
while(scanf("%f", &input)==1 && input != 999.f){
if (CHECK(input, A)){
++COUNTER(A);
} else if(CHECK(input, B)){
++COUNTER(B);
} else if(CHECK(input, C)){
++COUNTER(C);
} else if(CHECK(input, D)){
++COUNTER(D);
} else if(CHECK(input, F)){
++COUNTER(F);
}
}
DISP(A);
DISP(B);
DISP(C);
DISP(D);
DISP(F);
return 0;
}
Try Something Like This
#define F_Range(x) (x>=0 && x<=49)?true:false
#define D_Range(x) (x>=50 && x<=59)?true:false
#define C_Range(x) (x>=60 && x<=69)?true:false
#define B_Range(x) (x>=70 && x<=79)?true:false
#define A_Range(x) (x>=80 && x<=89)?true:false
AND
scanf("%f",&input); //Get input from user
if (F_Range(input));
{
F_Counter++;
}
else if (D_Range(input))
{
D_Counter++;
}
else if (C_Range(input))
{
C_Counter++;
}
else if (B_Range(input))
{
B_Counter++;
}
else if (A_Range(input))
{
A_Counter++;
}
I have a C program with some definitions for error codes. Like this:
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
#define ...
#define ...
Is it possible to print the name of the definition by its value? Like this:
PRINT_NAME(-2);
// output
FILE_NOT_FOUND
In short, no. The easiest way to do this would be something like so (PLEASE NOTE: this assumes that you can never have an error assigned to zero/null):
//Should really be wrapping numerical definitions in parentheses.
#define FILE_NOT_FOUND (-2)
#define FILE_INVALID (-3)
#define INTERNAL_ERROR (-4)
typdef struct {
int errorCode;
const char* errorString;
} errorType;
const errorType[] = {
{FILE_NOT_FOUND, "FILE_NOT_FOUND" },
{FILE_INVALID, "FILE_INVALID" },
{INTERNAL_ERROR, "INTERNAL_ERROR" },
{NULL, "NULL" },
};
// Now we just need a function to perform a simple search
int errorIndex(int errorValue) {
int i;
bool found = false;
for(i=0; errorType[i] != NULL; i++) {
if(errorType[i].errorCode == errorValue) {
//Found the correct error index value
found = true;
break;
}
}
if(found) {
printf("Error number: %d (%s) found at index %d",errorType[i].errorCode, errorType[i].errorString, i);
} else {
printf("Invalid error code provided!");
}
if(found) {
return i;
} else {
return -1;
}
}
Enjoy!
Additionally, if you wanted to save on typing even more, you could use a preprocessor macro to make it even neater:
#define NEW_ERROR_TYPE(ERR) {ERR, #ERR}
const errorType[] = {
NEW_ERROR_TYPE(FILE_NOT_FOUND),
NEW_ERROR_TYPE(FILE_INVALID),
NEW_ERROR_TYPE(INTERNAL_ERROR),
NEW_ERROR_TYPE(NULL)
};
Now you only have to type the macro name once, reducing the chance of typos.
You can do something like this.
#include <stdio.h>
#define FILE_NOT_FOUND -2
#define FILE_INVALID -3
#define INTERNAL_ERROR -4
const char* name(int value) {
#define NAME(ERR) case ERR: return #ERR;
switch (value) {
NAME(FILE_NOT_FOUND)
NAME(FILE_INVALID)
NAME(INTERNAL_ERROR)
}
return "unknown";
#undef NAME
}
int main() {
printf("==== %d %s %s\n", FILE_NOT_FOUND, name(FILE_NOT_FOUND), name(-2));
}
No, that's not possible. What would this print?
#define FILE_NOT_FOUND 1
#define UNIT_COST 1
#define EGGS_PER_RATCHET 1
PRINT_NAME(1);
Kinda ...
#define ERROR_CODE_1 "FILE_NOT_FOUND"
#define ERROR_CODE_2 "FILE_FOUND"
#define PRINT_NAME(N) ERROR_CODE_ ## N
or:
static char* error_codes(int err) {
static char name[256][256] = {
};
int base = .... lowest error code;
return name[err - base];
}
#define PRINT_NAME(N) error_code(N)
Why not elect to use an enumeration instead?
enum errors {FILE_NOT_FOUND = -2, FILE_INVALID = -3, INTERNAL_ERROR = -4};
FILE *fp = fopen("file.txt", "r");
if(fp == NULL) {
printf("Error\n");
exit(FILE_NOT_FOUND);
}
Not automatically. The name is losing during compilation, and only the constant number remains in the code.
But you can build something like this:
const char * a[] = {"","","FILE_NOT_FOUND","FILE_INVALID"};
and access it by using the define value absolute value as index.
Use designated initializers of C99 for this, but a bit of care is necessary if your error codes are negative.
First a version for positive values:
#define CODE(C) [C] = #C
static
char const*const codeArray[] = {
CODE(EONE),
CODE(ETWO),
CODE(ETHREE),
};
enum { maxCode = (sizeof codeArray/ sizeof codeArray[0]) };
This allocates an array with the length that you need and with the string pointers at the right positions. Note that duplicate values are allowed by the standard, the last one would be the one that is actually stored in the array.
To print an error code, you'd have to check if the index is smaller than maxCode.
If your error codes are always negative you'd just have to negate the code before printing. But it is probably a good idea to do it the other way round: have the codes to be positive and check a return value for its sign. If it is negative the error code would be the negation of the value.
This is how I do it in C:
< MyDefines.h >
#pragma once
#ifdef DECLARE_DEFINE_NAMES
// Switch-case macro for getting defines names
#define BEGIN_DEFINE_LIST const char* GetDefineName (int key) { switch (key) {
#define MY_DEFINE(name, value) case value: return #name;
#define END_DEFINE_LIST } return "Unknown"; }
#else
// Macros for declaring defines
#define BEGIN_COMMAND_LIST /* nothing */
#define MY_DEFINE(name, value) static const int name = value;
#define END_COMMAND_LIST /* nothing */
#endif
// Declare your defines
BEGIN_DEFINE_LIST
MY_DEFINE(SUCCEEDED, 0)
MY_DEFINE(FAILED, -1)
MY_DEFINE(FILE_NOT_FOUND, -2)
MY_DEFINE(INVALID_FILE, -3)
MY_DEFINE(INTERNAL_ERROR -4)
etc...
END_DEFINE_LIST
< MyDefineInfo.h >
#pragma once
const char* GetDefineName(int key);
< MyDefineInfo.c >
#define DECLARE_DEFINE_NAMES
#include "MyDefines.h"
Now, you can use the declared switch-case macro wherever like this:
< WhereEver.c >
#include "MyDefines.h"
#include "MyDefineInfo.h"
void PrintThings()
{
Print(GetDefineName(SUCCEEDED));
Print(GetDefineName(INTERNAL_ERROR));
Print(GetDefineName(-1);
// etc.
}
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)