I wrote a program in C that uses a number of different random number generators and one of them is ISAAC (available at http://burtleburtle.net/bob/rand/isaacafa.html). It works well but the problem is that in rand.h rand() is redefined as a macro. In my program I want to use the standard C rand() function as well. I tried changing the name of the macro to rand12() but I cannot see any other place in ISAAC that the macro is called so this doesn't work.
Could you offer some ideas how I can keep the standard rand() function and use ISAAC as well?
Given that the header rand.h contains:
#ifndef STANDARD
#include "standard.h"
#endif
#ifndef RAND
#define RAND
#define RANDSIZL (8)
#define RANDSIZ (1<<RANDSIZL)
/* context of random number generator */
struct randctx
{
ub4 randcnt;
ub4 randrsl[RANDSIZ];
ub4 randmem[RANDSIZ];
ub4 randa;
ub4 randb;
ub4 randc;
};
typedef struct randctx randctx;
/* If (flag==TRUE), then use the contents of randrsl[0..RANDSIZ-1] as the seed. */
void randinit(/*_ randctx *r, word flag _*/);
void isaac(/*_ randctx *r _*/);
/* Call rand(/o_ randctx *r _o/) to retrieve a single 32-bit random value */
#define rand(r) \
(!(r)->randcnt-- ? \
(isaac(r), (r)->randcnt=RANDSIZ-1, (r)->randrsl[(r)->randcnt]) : \
(r)->randrsl[(r)->randcnt])
#endif /* RAND */
You are going to need to do some work to the code to be able to use it alongside rand() from <stdlib.h>. The interface to the ISAAC rand() is different from the interface to rand() from <stdlib.h> too.
Create yourself a new header, "isaac.h", which defines cover functions to handle the peculiarities of the ISAAC system.
Maybe, if you aren't going to be working in a threaded context
#ifndef ISAAC_H_INCLUDED
#define ISAAC_H_INCLUDED
extern void isaac_init(unsigned long seed);
extern int isaac_rand(void);
#endif
You then implement those functions in isaac.c such that they call down onto the functions defined in rand.h, and isaac_rand() contains an invocation of the rand() macro from rand.h (providing a context from somewhere, which is where the non-threaded part comes in). You can decide what to do with the seed, or whether to change the seeding mechanism.
You can then use the isaac_init() and isaac_rand() functions in your code, as well as the normal rand() and srand().
I'd also upgrade the code in rand.h to provide full prototypes for the functions in the package. The commented prototypes is a legacy from when it was first written, back in the mid-90s, when standard C compilers were not universally accessible. The earliest date in the header is 1996; that's just on the cusp of when standard C compilers became almost universally available.
I note that the comments in the header (removed above) say the code is in the public domain; that means it is 100% legitimate to make any modifications you need.
isaac.c
#include "isaac.h"
#include "rand.h"
static randctx control;
void isaac_init(unsigned long seed)
{
assert(seed != 0);
randinit(&control, FALSE);
}
int isaac_rand(void)
{
return rand(&control);
}
This implementation ignores the seed you give, mainly because the structure expects eight 32-bit numbers to seed the randrsl member of the context structure (the one I called control). You could do something like use the seed value 8 times in a row instead of completely ignoring it, or add some number to it each time, or whatever other more complex seeding technique. You should seriously look at using /dev/urandom as a source of the seed:
#define DEV_URANDOM "/dev/urandom"
int ur = open(DEV_URANDOM, O_RDONLY);
if (ur >= 0)
{
read(ur, control.randrsl, sizeof(control.randrsl));
close(ur);
}
You'd put this code into isaac_init() before the call to randinit(), and you'd change the FALSE to TRUE. You'd probably also lose the seed argument to the isaac_init() function.
This leaves you with a problem of tracking the random seed to gain reproducibility (which can be important when debugging). That's for you to resolve, though — there are multiple ways to do that. You might have two initialize functions: void isaac_init(void) and void isaac_rsl(unsigned int *rsl) which takes an array of 8 unsigned int (or ub4) values and uses that as the seed instead of the output of /dev/urandom. Or you could pass a null pointer to mean "use output from /dev/urandom" and a non-null pointer to mean "use the values I've provided". Etc.
Related
Is there a way to add an identifier that the compiler would replace with multiple lines of code?
I read up on macros and inline functions but am getting no where.
I need to write an Interrupt Service Routine and not call any functions for speed.
Trouble is I have several cases where I need to use a function so currently I just repeat all several lines in many places.
for example:
void ISR()
{
int a = 1;
int b = 2;
int c = 3;
// do some stuff here ...
int a = 1;
int b = 2;
int c = 3;
// do more stuff here ...
int a = 1;
int b = 2;
int c = 3;
}
The function is many pages and I need the code to be more readable.
I basically agree with everyone else's reservations with regards to using macros for this. But, to answer your question, Multiline macros can be created with a backslash.
#define INIT_VARS \
int a = 1; \
int b = 2; \
int c = 3;
#define RESET_VARS \
a = 1; \
b = 2; \
c = 3;
void ISR()
{
INIT_VARS
// do some stuff here ...
RESET_VARS
// do more stuff here ...
RESET_VARS
}
You can use inline function that will be rather integrated into place where it is called in source instead of really being called (note that behavior of this depends on several things like compiler support and optimizations setup or using -fno-inline flag feature). GCC documentation on inline functions.
For completeness - other way would be defining // do some stuff here... as pre-processor macro which again gets inserted in place where called; this time by preprocessor - so no type safety, harder to debug and also to read. Usual good rule of thumb is to not write a macro for something that can be done with function.
You are correct - it is recommended that you not place function calls in an ISR. It's not that you cannot do it, but it can be a memory burden depending on the type of call. The primary reason is for timing. ISRs should be quick in and out. You shouldn't be doing a lot of extended work inside them.
That said, here's how you can actually use inline functions.
// In main.c
#include static_defs.h
//...
void ISR() {
inline_func();
// ...
inline_func();
}
// In static_defs.h
static inline void inline_func(void) __attribute__((always_inline));
// ... Further down in file
static inline void inline_func(void) {
// do stuff
}
The compiler will basically just paste the "do stuff" code into the ISR multiple times, but as I said before, if it's a complex function, it's probably not a good idea to do it multiple times in a single ISR, inlined or not. It might be better to set a flag of some sort and do it in your main loop so that other interrupts can do their job, too. Then, you can use a normal function to save program memory space. That depends on what you are really doing and when/why it needs done.
If you are actually setting variables and returning values, that's fine too, although, setting multiple variables would be done by passing/returning a structure or using a pointer to a structure that describes all of the relevant variables.
If you'd prefer to use macros (I wouldn't, because function-like macros should be avoided), here's an example of that:
#define RESET_VARS() do { \
a = 1; \
b = 2; \
c = 3; \
while (0)
//...
void ISR() {
uint8_t a=1, b=2, c=3;
RESET_VARS();
// ...
RESET_VARS();
}
Also, you said it was a hypothetical, but it's recommended to use the bit-width typedefs found in <stdint.h> (automatically included when you include <io.h> such as uint8_t rather than int. On an 8-bit MCU with AVR-GCC, an int is a 16-bit signed variable, which will require (at least) 2 clock cycles for every operation that would have taken one with an 8-bit variable.
Nginx seems to have a built-in function called ngx_random that's used in various places of the source code. But it seems just to be defined as:#define ngx_random random
If I'm understanding this correctly, that means all the places Nginx calling ngx_random() it's just calling (on Linux platform) random(). From the doc it isn't clear to me that it is guaranteed uniform distribution with a given range in any way, and I'm suspecting that similar to rand(), it's not uniform at all, and will only be uniform if range n is divisible by RAND_MAX.
But the nice thing of using ngx_random is I believe the system takes care of the seeding automatically, during startup time. Whereas if I want to use something truly uniform with my range, like drand48, I believe will have to add a new line after the following in ngx_posix_init.c?
srandom(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec);
srand48(((unsigned) ngx_pid << 16) ^ tp->sec ^ tp->msec); //Added so that I can use drand48
So is my assumption on ngx_random correct? And if I want to use drand48 in any place of the various modules, is the above the only way doing it?
I never tried it myself with nginx, so consider it just an idea. On Linux (or similar ELF based systems, e.g. Solaris) you could, using LD_LIBRARY_PRELOAD trick, to replace and/or intercept weak symbols from standard C library. It is often used to intercept and/or replace malloc, but might work for you as well
Code sample (untested, not compiled, just to demonstrate an idea)
#define _GNU_SOURCE
#include <stdlib.h>
#include <dlfcn.h>
static void (*real_srandom)(uint32_t) = NULL;
static void srandom_init(void) {
real_srandom = dlsym(RTLD_NEXT, "srandom");
if (NULL == real_srandom) {
fprintf(stderr, "Error in `dlsym`: %s\n", dlerror());
}
}
void srandom(uint32_t seed) {
if(real_srandom == NULL) {
srandom_init();
}
real_srandom(seed);
srand48(seed);
}
You could write SO to replace calls to random(3) as well, replacing it with your own implementation. The only thing you cannot replace is RAND_MAX, as it is compiled in constant.
I would be happy to hear if this trick works for you or not
I need a 'good' way to initialize the pseudo-random number generator in C++. I've found an article that states:
In order to generate random-like
numbers, srand is usually initialized
to some distinctive value, like those
related with the execution time. For
example, the value returned by the
function time (declared in header
ctime) is different each second, which
is distinctive enough for most
randoming needs.
Unixtime isn't distinctive enough for my application. What's a better way to initialize this? Bonus points if it's portable, but the code will primarily be running on Linux hosts.
I was thinking of doing some pid/unixtime math to get an int, or possibly reading data from /dev/urandom.
Thanks!
EDIT
Yes, I am actually starting my application multiple times a second and I've run into collisions.
This is what I've used for small command line programs that can be run frequently (multiple times a second):
unsigned long seed = mix(clock(), time(NULL), getpid());
Where mix is:
// Robert Jenkins' 96 bit Mix Function
unsigned long mix(unsigned long a, unsigned long b, unsigned long c)
{
a=a-b; a=a-c; a=a^(c >> 13);
b=b-c; b=b-a; b=b^(a << 8);
c=c-a; c=c-b; c=c^(b >> 13);
a=a-b; a=a-c; a=a^(c >> 12);
b=b-c; b=b-a; b=b^(a << 16);
c=c-a; c=c-b; c=c^(b >> 5);
a=a-b; a=a-c; a=a^(c >> 3);
b=b-c; b=b-a; b=b^(a << 10);
c=c-a; c=c-b; c=c^(b >> 15);
return c;
}
The best answer is to use <random>. If you are using a pre C++11 version, you can look at the Boost random number stuff.
But if we are talking about rand() and srand()
The best simplest way is just to use time():
int main()
{
srand(time(nullptr));
...
}
Be sure to do this at the beginning of your program, and not every time you call rand()!
Side Note:
NOTE: There is a discussion in the comments below about this being insecure (which is true, but ultimately not relevant (read on)). So an alternative is to seed from the random device /dev/random (or some other secure real(er) random number generator). BUT: Don't let this lull you into a false sense of security. This is rand() we are using. Even if you seed it with a brilliantly generated seed it is still predictable (if you have any value you can predict the full sequence of next values). This is only useful for generating "pseudo" random values.
If you want "secure" you should probably be using <random> (Though I would do some more reading on a security informed site). See the answer below as a starting point: https://stackoverflow.com/a/29190957/14065 for a better answer.
Secondary note: Using the random device actually solves the issues with starting multiple copies per second better than my original suggestion below (just not the security issue).
Back to the original story:
Every time you start up, time() will return a unique value (unless you start the application multiple times a second). In 32 bit systems, it will only repeat every 60 years or so.
I know you don't think time is unique enough but I find that hard to believe. But I have been known to be wrong.
If you are starting a lot of copies of your application simultaneously you could use a timer with a finer resolution. But then you run the risk of a shorter time period before the value repeats.
OK, so if you really think you are starting multiple applications a second.
Then use a finer grain on the timer.
int main()
{
struct timeval time;
gettimeofday(&time,NULL);
// microsecond has 1 000 000
// Assuming you did not need quite that accuracy
// Also do not assume the system clock has that accuracy.
srand((time.tv_sec * 1000) + (time.tv_usec / 1000));
// The trouble here is that the seed will repeat every
// 24 days or so.
// If you use 100 (rather than 1000) the seed repeats every 248 days.
// Do not make the MISTAKE of using just the tv_usec
// This will mean your seed repeats every second.
}
if you need a better random number generator, don't use the libc rand. Instead just use something like /dev/random or /dev/urandom directly (read in an int directly from it or something like that).
The only real benefit of the libc rand is that given a seed, it is predictable which helps with debugging.
On windows:
srand(GetTickCount());
provides a better seed than time() since its in milliseconds.
C++11 random_device
If you need reasonable quality then you should not be using rand() in the first place; you should use the <random> library. It provides lots of great functionality like a variety of engines for different quality/size/performance trade-offs, re-entrancy, and pre-defined distributions so you don't end up getting them wrong. It may even provide easy access to non-deterministic random data, (e.g., /dev/random), depending on your implementation.
#include <random>
#include <iostream>
int main() {
std::random_device r;
std::seed_seq seed{r(), r(), r(), r(), r(), r(), r(), r()};
std::mt19937 eng(seed);
std::uniform_int_distribution<> dist{1,100};
for (int i=0; i<50; ++i)
std::cout << dist(eng) << '\n';
}
eng is a source of randomness, here a built-in implementation of mersenne twister. We seed it using random_device, which in any decent implementation will be a non-determanistic RNG, and seed_seq to combine more than 32-bits of random data. For example in libc++ random_device accesses /dev/urandom by default (though you can give it another file to access instead).
Next we create a distribution such that, given a source of randomness, repeated calls to the distribution will produce a uniform distribution of ints from 1 to 100. Then we proceed to using the distribution repeatedly and printing the results.
Best way is to use another pseudorandom number generator.
Mersenne twister (and Wichmann-Hill) is my recommendation.
http://en.wikipedia.org/wiki/Mersenne_twister
i suggest you see unix_random.c file in mozilla code. ( guess it is mozilla/security/freebl/ ...) it should be in freebl library.
there it uses system call info ( like pwd, netstat ....) to generate noise for the random number;it is written to support most of the platforms (which can gain me bonus point :D ).
The real question you must ask yourself is what randomness quality you need.
libc random is a LCG
The quality of randomness will be low whatever input you provide srand with.
If you simply need to make sure that different instances will have different initializations, you can mix process id (getpid), thread id and a timer. Mix the results with xor. Entropy should be sufficient for most applications.
Example :
struct timeb tp;
ftime(&tp);
srand(static_cast<unsigned int>(getpid()) ^
static_cast<unsigned int>(pthread_self()) ^
static_cast<unsigned int >(tp.millitm));
For better random quality, use /dev/urandom. You can make the above code portable in using boost::thread and boost::date_time.
The c++11 version of the top voted post by Jonathan Wright:
#include <ctime>
#include <random>
#include <thread>
...
const auto time_seed = static_cast<size_t>(std::time(0));
const auto clock_seed = static_cast<size_t>(std::clock());
const size_t pid_seed =
std::hash<std::thread::id>()(std::this_thread::get_id());
std::seed_seq seed_value { time_seed, clock_seed, pid_seed };
...
// E.g seeding an engine with the above seed.
std::mt19937 gen;
gen.seed(seed_value);
#include <stdio.h>
#include <sys/time.h>
main()
{
struct timeval tv;
gettimeofday(&tv,NULL);
printf("%d\n", tv.tv_usec);
return 0;
}
tv.tv_usec is in microseconds. This should be acceptable seed.
As long as your program is only running on Linux (and your program is an ELF executable), you are guaranteed that the kernel provides your process with a unique random seed in the ELF aux vector. The kernel gives you 16 random bytes, different for each process, which you can get with getauxval(AT_RANDOM). To use these for srand, use just an int of them, as such:
#include <sys/auxv.h>
void initrand(void)
{
unsigned int *seed;
seed = (unsigned int *)getauxval(AT_RANDOM);
srand(*seed);
}
It may be possible that this also translates to other ELF-based systems. I'm not sure what aux values are implemented on systems other than Linux.
Suppose you have a function with a signature like:
int foo(char *p);
An excellent source of entropy for a random seed is a hash of the following:
Full result of clock_gettime (seconds and nanoseconds) without throwing away the low bits - they're the most valuable.
The value of p, cast to uintptr_t.
The address of p, cast to uintptr_t.
At least the third, and possibly also the second, derive entropy from the system's ASLR, if available (the initial stack address, and thus current stack address, is somewhat random).
I would also avoid using rand/srand entirely, both for the sake of not touching global state, and so you can have more control over the PRNG that's used. But the above procedure is a good (and fairly portable) way to get some decent entropy without a lot of work, regardless of what PRNG you use.
For those using Visual Studio here's yet another way:
#include "stdafx.h"
#include <time.h>
#include <windows.h>
const __int64 DELTA_EPOCH_IN_MICROSECS= 11644473600000000;
struct timezone2
{
__int32 tz_minuteswest; /* minutes W of Greenwich */
bool tz_dsttime; /* type of dst correction */
};
struct timeval2 {
__int32 tv_sec; /* seconds */
__int32 tv_usec; /* microseconds */
};
int gettimeofday(struct timeval2 *tv/*in*/, struct timezone2 *tz/*in*/)
{
FILETIME ft;
__int64 tmpres = 0;
TIME_ZONE_INFORMATION tz_winapi;
int rez = 0;
ZeroMemory(&ft, sizeof(ft));
ZeroMemory(&tz_winapi, sizeof(tz_winapi));
GetSystemTimeAsFileTime(&ft);
tmpres = ft.dwHighDateTime;
tmpres <<= 32;
tmpres |= ft.dwLowDateTime;
/*converting file time to unix epoch*/
tmpres /= 10; /*convert into microseconds*/
tmpres -= DELTA_EPOCH_IN_MICROSECS;
tv->tv_sec = (__int32)(tmpres * 0.000001);
tv->tv_usec = (tmpres % 1000000);
//_tzset(),don't work properly, so we use GetTimeZoneInformation
rez = GetTimeZoneInformation(&tz_winapi);
tz->tz_dsttime = (rez == 2) ? true : false;
tz->tz_minuteswest = tz_winapi.Bias + ((rez == 2) ? tz_winapi.DaylightBias : 0);
return 0;
}
int main(int argc, char** argv) {
struct timeval2 tv;
struct timezone2 tz;
ZeroMemory(&tv, sizeof(tv));
ZeroMemory(&tz, sizeof(tz));
gettimeofday(&tv, &tz);
unsigned long seed = tv.tv_sec ^ (tv.tv_usec << 12);
srand(seed);
}
Maybe a bit overkill but works well for quick intervals. gettimeofday function found here.
Edit: upon further investigation rand_s might be a good alternative for Visual Studio, it's not just a safe rand(), it's totally different and doesn't use the seed from srand. I had presumed it was almost identical to rand just "safer".
To use rand_s just don't forget to #define _CRT_RAND_S before stdlib.h is included.
Assuming that the randomness of srand() + rand() is enough for your purposes, the trick is in selecting the best seed for srand. time(NULL) is a good starting point, but you'll run into problems if you start more than one instance of the program within the same second. Adding the pid (process id) is an improvement as different instances will get different pids. I would multiply the pid by a factor to spread them more.
But let's say you are using this for some embedded device and you have several in the same network. If they are all powered at once and you are launching the several instances of your program automatically at boot time, they may still get the same time and pid and all the devices will generate the same sequence of "random" numbers. In that case, you may want to add some unique identifier of each device (like the CPU serial number).
The proposed initialization would then be:
srand(time(NULL) + 1000 * getpid() + (uint) getCpuSerialNumber());
In a Linux machine (at least in the Raspberry Pi where I tested this), you can implement the following function to get the CPU Serial Number:
// Gets the CPU Serial Number as a 64 bit unsigned int. Returns 0 if not found.
uint64_t getCpuSerialNumber() {
FILE *f = fopen("/proc/cpuinfo", "r");
if (!f) {
return 0;
}
char line[256];
uint64_t serial = 0;
while (fgets(line, 256, f)) {
if (strncmp(line, "Serial", 6) == 0) {
serial = strtoull(strchr(line, ':') + 2, NULL, 16);
}
}
fclose(f);
return serial;
}
Include the header at the top of your program, and write:
srand(time(NULL));
In your program before you declare your random number. Here is an example of a program that prints a random number between one and ten:
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
//Initialize srand
srand(time(NULL));
//Create random number
int n = rand() % 10 + 1;
//Print the number
cout << n << endl; //End the line
//The main function is an int, so it must return a value
return 0;
}
GNU libc's backtrace and In-circuit emulators/debuggers are not always available when porting code to a new platform, especially when the target is a micro C compiler such as for the Z80. (Typically a program bug would "just hang" somewhere, or crash the gadget.)
Is there an alternative to the classic "wolf fencing" method of manually inserting printf? Something simple and portable (using no C extensions) that a coder can do while developing a program that includes tracing and backtracing into a C program?
BTW: Here are a couple of other question on stackoverflow that are related, but these both use GNU GLIBC's backtrace and backtrace is often compiler/implementation specific:
Is there a function to invoke a stack dump in C?
How to generate a stacktrace when my gcc C++ app crashes
Here is the kernel of the kernel of my answer: write some code.
The kernel of my answer is: If your compiler allocates locals on the stack always, then...
Add blobs to the stack at every function entry that record the name of the function, throw in some magic numbers to maybe catch stack smashes.
typedef struct stack_debug_blob_ {
int magic1;
const char * function_name;
int magic2;
struct stack_debug_blob_ * called_by;
int magic3;
} stack_debug_blob;
stack_debug_blob * top_of_stack_debug_blobs = 0;
Create a macro ENTER(f) taking the name of the function. The macro should be about the first line of code in every function after the opening {. It adds a struct with a pointer to the (const) char * function name, a pointer to the previous struct on the stack, and maybe some magic numbers to check sanity. Make the top of blob stack pointer point at this new struct.
#define ENTER(f) \
stack_debug_blob new_stack_debug_blob = { \
MAGIC1, (f), MAGIC2, top_of_stack_debug_blobs, MAGIC3}; \
stack_debug_blob * evil_hack = (top_of_stack_debug_blobs = (&new_stack_debug_blob))
To keep things as portable as possible, all ENTER can do is declare and initialize variables. Hence the evil_hack to do a little extra computation than just initializing a variable.
Create a function to walk down the list of blobs checking pointers and magic numbers. It should signal an error (maybe print to stderr, maybe lockup the cpu with while (1) { /* nada */ }, maybe enter the debugger... depends on your hardware) if it finds things messed up.
Create a macro EXIT() that checks your stack of blobs, then de-links the topmost from the linked list. It needs to be put at the exit points of all your functions.
#define EXIT() do { \
check_debug_blobs(); \
top_of_stack_debug_blobs = new_stack_debug_blob.called_by; \
new_stack_debug_blob.magic1 -= 1; /* paranoia */ \
} while (0)
Probably will also need to replace all return's with RETURN macro calls, the RETURN macro is just like EXIT, but has a return before the } while (0).
Create a function to walk down the list of blobs printing out the function names, call it something like stacktrace or backtrace maybe.
Write a program to instrument your C code with calls to ENTER(f) and EXIT() and RETURN(x).
Left out a few details to let you have fun with it...
See also Any porting available of backtrace for uclibc?
There is an implementation at RosettaCode.org which uses the same basic idea as #jsl4tv's suggestion.
Example, given the following classic C code with built in "hang":
#include <stdio.h>
#include <stdlib.h>
void inner(int k)
{
for(;;){} /* hang */
}
void middle(int x, int y)
{
inner(x*y);
}
void outer(int a, int b, int c)
{
middle(a+b, b+c);
}
int main()
{
outer(2,3,5);
return(EXIT_SUCCESS);
}
#define STACK_TRACE_ON and #include "stack_trace.h" from RosettaCode.org then insert BEGIN(f)/ENDs where required:
#include <stdio.h>
#include <stdlib.h>
#define STACK_TRACE_ON /* compile in these "stack_trace" routines */
#include "stack_trace.h"
void inner(int k)
BEGIN(inner)
print_indent(); printf("*** Now dump the stack ***\n");
print_stack_trace();
for(;;){} /* hang */
END
void middle(int x, int y)
BEGIN(middle)
inner(x*y);
END
void outer(int a, int b, int c)
BEGIN(outer)
middle(a+b, b+c);
END
int main()
BEGIN(main)
stack_trace.on = TRUE; /* turn on runtime tracing */
outer(2,3,5);
stack_trace.on = FALSE;
RETURN(EXIT_SUCCESS);
END
Produces:
stack_trace_test.c:19: BEGIN outer[0x80487b4], stack(depth:1, size:60)
stack_trace_test.c:14: BEGIN middle[0x8048749], stack(depth:2, size:108)
stack_trace_test.c:8: BEGIN inner[0x80486d8], stack(depth:3, size:156)
stack_trace_test.c:8: *** Now dump the stack ***
stack_trace_test.c:8: inner[0x80486d8] --- stack(depth:4, size:156) ---
stack_trace_test.c:14: middle[0x8048749] --- stack(depth:3, size:108) ---
stack_trace_test.c:19: outer[0x80487b4] --- stack(depth:2, size:60) ---
stack_trace_test.c:24: main[0x804882a] --- stack(depth:1, size:0) ---
stack_trace_test.c:8: --- (depth 4) ---
A well polished [open source] version of this BEGIN ~ END method would be perfect. (Esp if it has a "FINALLY" clause for exception handling).
Hints/URLs appreciated.
on Symbian there were some scripts made to go over the registers and stack looking for things that looked like code addresses.
This is not portable, but it doesn't depend on decorating the code either. This was a necessary tradeoff on a platform where byte counts mattered... and it wasn't nearly as limited as Z80! But limited enough to compile without frame-pointers and such.
To calculate a backtrace from a stack without frame-pointers you have to work up the stack not down it.
Is there a way to get the C/C++ preprocessor or a template or such to mangle/hash the __FILE__ and __LINE__ and perhaps some other external input like a build-number into a single short number that can be quoted in logs or error messages?
(The intention would be to be able to reverse it (to a list of candidates if its lossy) when needed when a customer quotes it in a bug report.)
You will have to use a function to perform the hashing and create a code from __LINE__ and __FILE__ as the C preprocessor is not able to do such complex tasks.
Anyway, you can take inspiration by this article to see if a different solution can be better suited to your situation.
Well... you could use something like:
((*(int*)__FILE__ && 0xFFFF0000) | version << 8 | __LINE__ )
It wouldn't be perfectly unique, but it might work for what you want. Could change those ORs to +, which might work better for some things.
Naturally, if you can actually create a hashcode, you'll probably want to do that.
I needed serial valuse in a project of mine and got them by making a template that specialized on __LINE__ and __FILE__ and resulted in an int as well as generating (as compile time output to stdout) a template specialization for it's inputs that resulted in the line number of that template. These were collected the first time through the compiler and then dumped into a code file and the program was compiled again. That time each location that the template was used got a different number.
(done in D so it might not be possible in C++)
template Serial(char[] file, int line)
{
prgams(msg,
"template Serial(char[] file : \"~file~"\", int line : "~line.stringof~")"
"{const int Serial = __LINE__;");
const int Serial = -1;
}
A simpler solution would be to keep a global static "error location" variable.
#ifdef DEBUG
#define trace_here(version) printf("[%d]%s:%d {%d}\n", version, __FILE__, __LINE__, errloc++);
#else
#define trace_here(version) printf("{%lu}\n", version<<16|errloc++);
#endif
Or without the printf.. Just increment the errloc everytime you cross a tracepoint. Then you can correlate the value to the line/number/version spit out by your debug builds pretty easily.
You'd need to include version or build number, because those error locations could change with any build.
Doesn't work well if you can't reproduce the code paths.
__FILE__ is a pointer into the constants segment of your program. If you output the difference between that and some other constant you should get a result that's independent of any relocation, etc:
extern const char g_DebugAnchor;
#define FILE_STR_OFFSET (__FILE__ - &g_DebugAnchor)
You can then report that, or combine it in some way with the line number, etc. The middle bits of FILE_STR_OFFSET are likely the most interesting.
Well, if you're displaying the message to the user yourself (as opposed to having a crash address or function be displayed by the system), there's nothing to keep you from displaying exactly what you want.
For example:
typedef union ErrorCode {
struct {
unsigned int file: 15;
unsigned int line: 12; /* Better than 5 bits, still not great
Thanks commenters!! */
unsigned int build: 5;
} bits;
unsigned int code;
} ErrorCode;
unsigned int buildErrorCodes(const char *file, int line, int build)
{
ErrorCode code;
code.bits.line=line & ((1<<12) - 1);
code.bits.build=build & ((1<< 5) - 1);
code.bits.file=some_hash_function(file) & ((1<<15) - 1);
return code.code;
}
You'd use that as
buildErrorCodes(__FILE__, __LINE__, BUILD_CODE)
and output it in hex. It wouldn't be very hard to decode...
(Edited -- the commenters are correct, I must have been nuts to specify 5 bits for the line number. Modulo 4096, however, lines with error messages aren't likely to collide. 5 bits for build is still fine - modulo 32 means that only 32 builds can be outstanding AND have the error still happen at the same line.)