LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 02-05-2017, 05:22 PM   #1
DeeDeeK
Member
 
Registered: Jan 2016
Distribution: Ubuntu 14.04
Posts: 37

Rep: Reputation: Disabled
Why won't this macro work in a simple comparison if(rx(n)>n1) but in these other cases?


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.
 
Old 02-05-2017, 10:34 PM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,869
Blog Entries: 1

Rep: Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870Reputation: 1870
That's what gdb is good for. Use low-level features like 'disass' and 'info registers'
 
Old 02-08-2017, 09:28 PM   #3
DeeDeeK
Member
 
Registered: Jan 2016
Distribution: Ubuntu 14.04
Posts: 37

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by NevemTeve View Post
That's what gdb is good for. Use low-level features like 'disass' and 'info registers'

That makes sense. Now I've got something new to learn about.

What I should have asked, tho' is does anyone know about this feature ({[your compound statement]}) and how it works. Such as is there a difference between what it coughs up and what an inlined function coughs up. Or a not-inlined function.

The solution to the problem of how to make my code work is to use the thing which works. So no need for gdb I guess, tho' I'd be interested.

Even more puzzling is this macro. It works where the one I was curious about didn't.


Code:
#define rx(__x) \
	({__x ? ({unsigned long intermediate = rand();\
	intermediate *= (abs(__x)+1);\
	intermediate /= INT_MAX;}):0;})
 
Old 02-08-2017, 10:19 PM   #4
norobro
Member
 
Registered: Feb 2006
Distribution: Debian Sid
Posts: 792

Rep: Reputation: 331Reputation: 331Reputation: 331Reputation: 331
Paring your original code down to a bare minimum, I don't get a segfault either way on my machine.
Code:
#include <stdio.h>
#include <limits.h>
#include <stdlib.h>

#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){
    rand(); 
    int count = 0;
    for(;;){
        ++count;
//	if(IntRand(1000) > 999){ 
	if(rx(1000) > 999){ 
	    printf("loop iterated %d times.\n", count);
	    break;
	}
    }
    return NULL;
}

int main() {
    two_lthread_scheduler_coordinator(NULL);
}
 
Old 02-09-2017, 08:48 AM   #5
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,671
Blog Entries: 4

Rep: Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945Reputation: 3945
You can also ask to see the expanded macros. With gcc, that option is -E.

- - -

And, I guess that this is one reason why I really don't care for "macros" much anyway.

Last edited by sundialsvcs; 02-09-2017 at 06:01 PM.
 
Old 02-09-2017, 10:24 AM   #6
NoStressHQ
Member
 
Registered: Apr 2010
Location: Geneva - Switzerland ( Bordeaux - France / Montreal - QC - Canada)
Distribution: Slackware 14.2 - 32/64bit
Posts: 609

Rep: Reputation: 221Reputation: 221Reputation: 221
And what about simply:

Code:
#define rx(x) (x ? (((unsigned long)rand())*(abs(x)+1))/INT_MAX) : 0)
?
 
Old 02-11-2017, 03:44 PM   #7
DeeDeeK
Member
 
Registered: Jan 2016
Distribution: Ubuntu 14.04
Posts: 37

Original Poster
Rep: Reputation: Disabled
Quote:
Originally Posted by NoStressHQ View Post
And what about simply:

Code:
#define rx(x) (x ? (((unsigned long)rand())*(abs(x)+1))/INT_MAX) : 0)
?
One reason I don't do as you very aptly suggest is that I've been experimenting with the GCC feature which allows one to put a compound statement in between parentheses to work as an expression. I read that an advantage to a compound statement as an expression in a macro is that there's less to worry about as far as variable names go. That's why I declared a variable. Just practice.

This is/was an experiment and I'm having fun with it. Also I'm experimenting with the ternary operator. ?: is interesting and fun for me.

I'm teaching myself C programming on Linux mostly from books like The C Programming Language(2nd ed.), 21st Century C, Understanding C Pointers, Using the GNU Compiler Collection, and The Linux Programming Interface, and a couple of others so it's all very new to me.

The structured programming language I already knew is Modula-2, and I'm inclined to write much less succinct code, esp. when trying out new things.

I'm unsurprised norobro did not get a segfault. I think this is an idiosyncratic problem, related to a bunch of other things going wrong which don't make sense. I can't reproduce it anywhere else, not even in another function in the same program!

There are other things weird. I'm using lots of structs with pointers to functions in them and code does or does not work according to where the function pointers are put in the definition of the structs.

It seems like it's time for me to learn about gdb.
 
Old 02-11-2017, 04:11 PM   #8
DeeDeeK
Member
 
Registered: Jan 2016
Distribution: Ubuntu 14.04
Posts: 37

Original Poster
Rep: Reputation: Disabled
YOW! I just caught it. Or if not 'it,' one of 'them.' norobro's paring the code down must have got rid of segfault! I'm guess that since heartbeat is a local variable, it was a garbage value and since the init was expecting the pointer to be pointing to a valid pthread_cond_t. Or something. I guess I'm more new than I thought I was, to be making such mistakes.

Anyhow, it's fun and I'm learning, which is what a hobby is all about.

Here's the culprit two lines:
Code:
pthread_cond_t *heartbeat;
pthread_cond_init(heartbeat, NULL);
They should be this:
Code:
pthread_cond_t heartbeat;
pthread_cond_init(&heartbeat, NULL);
 
Old 02-11-2017, 07:23 PM   #9
NoStressHQ
Member
 
Registered: Apr 2010
Location: Geneva - Switzerland ( Bordeaux - France / Montreal - QC - Canada)
Distribution: Slackware 14.2 - 32/64bit
Posts: 609

Rep: Reputation: 221Reputation: 221Reputation: 221
Quote:
Originally Posted by DeeDeeK View Post
YOW! I just caught it.
Exactly, what you did is creating a local variable which is destroy at the end of the scope, and it's not a way to returns a value...

If you want to do "tricks" like these, you should try some stuff like those snippets:

Code:
#define SOME_MACRO_FUNC(_PARAM) do{ int localstuff; [...] _PARAM [...] }while(0)
Helpful when you want enforce macro user to have a semi-colon as if it was a normal function.

You can also do funny things with just the for( ; ; ) loop which is a "shortcut" to:
Code:
{
  for-init-code;
  while( for-continue-condition ) {
    for-block;
    for-next-statement;
  }
}
Using the right trick, you can make a macro which create "local variables" for the statement (or block) following your macro. This way you can write some kind of "foreach" macros.

It's a hobby for me too, 27 year on the counter, 20 years of being my job too, and still coding as addicted as if I was a teenager .

Bests.

Garry.

Last edited by NoStressHQ; 02-11-2017 at 07:24 PM. Reason: I hate it when "autosmileys" get into my code !!
 
Old 02-11-2017, 07:55 PM   #10
ntubski
Senior Member
 
Registered: Nov 2005
Distribution: Debian, Arch
Posts: 3,784

Rep: Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083Reputation: 2083
Quote:
Originally Posted by DeeDeeK View Post
YOW! I just caught it. Or if not 'it,' one of 'them.' norobro's paring the code down must have got rid of segfault! I'm guess that since heartbeat is a local variable, it was a garbage value and since the init was expecting the pointer to be pointing to a valid pthread_cond_t. Or something. I guess I'm more new than I thought I was, to be making such mistakes.
If you compile with -Wall then you get a warning like this:

Code:
pth.c:24:2: warning: ‘heartbeat’ is used uninitialized in this function [-Wuninitialized]
  pthread_cond_init(heartbeat, NULL);
  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
Apache2 VHOSTS Won't Work - Trying to make it simple pizzipie Linux - Server 4 06-07-2014 01:13 PM
[SOLVED] simple script won't work minty33 Linux - Newbie 5 09-30-2012 12:13 PM
[SOLVED] Simple problem getting a comparison operator to work atavus Programming 6 02-08-2010 02:28 PM
LXer: Ubuntu Karmic fail: Pidgin and the new Empathy won't run in some cases until yo LXer Syndicated Linux News 0 11-04-2009 09:30 PM
Simple script won't work compused Linux - Newbie 4 11-22-2006 06:52 AM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

All times are GMT -5. The time now is 06:38 PM.

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration