I made a macro to use instead of a function to generate a random number from 0 to x, given x.
I'm compiling with GCC 5.1.1, which allows declarations and code as a compound statement, between brackets, to be enclosed in parentheses to make an expression. The last thing in the compound statement has to be an expression, in this case the ?: operator in case x == 0 a 0 is returned.
I'm sure the macro isn't very sensible, but I was just trying out this nifty GCC feature. It makes it possible to use local variables and other good stuff in a macro without even trying that hard. I came across it on page 323 in Using the GNU Compiler Collection, chapter 6.1, but the edition I have is meant for GCC 4.8.1 and I wondered if that made any difference.
I know, this is a lot of information for what's probably a simple answer but I'm very interested in learning this stuff deeply and I'm looking all around for insight into GCC and C in general. C11 especially, and GCC's additions to the language.
the macro:
Code:
#define rx(x) \
({unsigned long intermediate = rand();\
intermediate *= (abs(x)+1);\
intermediate /= INT_MAX; x ? (int)intermediate:0;})
the function:
Code:
int IntRand( int maximum ){
if (!maximum)return 0;
unsigned long intermediate = rand();
intermediate *= (abs(maximum)+1);
intermediate /= INT_MAX;
return (int)intermediate;
}
here's where rx(x) won't work but IntRand() will:
Code:
if(IntRand(1000) > 999){ /*this works*/
signaller_command = signaller_quit;
}
Code:
if(rx(1000) > 999){ /*this gives me a segmentation fault*/
signaller_command = signaller_quit;
}
and if I write IntRand() this way, it works:
Code:
inline int IntRand( int maximum );
int IntRand( int maximum ){
return rx(maximum);
}
it also works if the function is not inlined. I inlined it to see if inlining would cause the same problem as the plain macro on its own has. It didn't.
So below is code snipped from my application. It runs with the commented out material commented out or not. The application performs very differently of course, but the same bug happens if rx(x) is used rather than when it is wrapped in a function.
I don't have any reason not to wrap it up, or any reason I must use it just as a macro. But I really want to understand why it's behaving this way!
Code:
#define rx(x) \
({unsigned long intermediate = rand();\
intermediate *= (abs(x)+1);\
intermediate /= INT_MAX; x ? (int)intermediate:0;})
inline int IntRand( int maximum );
int IntRand( int maximum ){
return rx(maximum);
}
void*
two_lthread_scheduler_coordinator(void *data){
static int signaller_command = signaller_null_command;
pthread_t launchthread1,
launchthread2;
pthread_cond_t *heartbeat;
pthread_cond_init(heartbeat, NULL);
int *cond_sig_frequency = data;
/*
signaller_info *siginfdata = malloc(sizeof(signaller_info));
printf("\nnow in two_lthread_scheduler_coordinator function\n");
siginfdata->bottom = 0;
siginfdata->range = 200;
siginfdata->command = &signaller_command;
siginfdata->pth_sync_signal = heartbeat;
siginfdata->self_execute = do_self;
pthread_create(&launchthread1, NULL, lthreads_scheduler_launcher, (void*)siginfdata);
siginfdata = malloc(sizeof(signaller_info));
siginfdata->bottom = 21;
siginfdata->range = 200;
siginfdata->command = &signaller_command;
siginfdata->pth_sync_signal = heartbeat;
siginfdata->self_execute = do_self;
pthread_create(&launchthread2, NULL, lthreads_scheduler_launcher, (void*)siginfdata);
*/
for(;;){
usleep(*cond_sig_frequency);
pthread_cond_signal(heartbeat);
if(IntRand(1000) > 999){ /* if(rx(1000) > 999){ */
signaller_command = signaller_quit;
break;
}
}
return NULL;
}
So if I swap the commented out code for the code where it says "if(IntRand(1000)" etc., it crashes. Otherwise, it runs fine. rx(n) works EVERYWHERE else, even in other comparisons!
Heck, I could post the entire 'application,' which is a pretty big word for about 240 lines of code. It's just a more refined, abstracted version of the code I posted asking about lthreads and pthreads in another thread. But I'm just asking about this issue with the macro and didn't want to accidentally start another thread about, well, threading.