code review:
>> #include <stdbool.h>
Suggestion: C99 only header. To make this explicit add:
Code:
#if __STDC_VERSION__ < 199901L
# error "C99 Source"
#endif
>> #ifdef WIN32
Your code is currently windows specific, so this isn't really needed. If you're really interested in running this code on multiple platforms, let us know. Otherwise remove anything that implies the code is multi-platform.
>> #define VAL_FORMAT "%I64u" (vs. "%llu")
The latest MS-CRT supports "%ll". For MS compilers, the best way (that I know of) to detect the major MS-CRT version is to check the compiler's version number. In this case the CRT that comes with VS-2005 and up supports "long long" and "%ll".
For MinGW (which uses the MS-CRT), they were nice enough to include a __MSVCRT_VERSION__ macro (from headers, not from compiler). They don't support the latest CRT, but perhaps someday. So a "better" conditional compile would be to detect when the non-standard I64 should be used, then default to the standard:
Code:
#if (defined(_MSC_VER) && (_MSC_VER < 1400)) || \
(defined(__MSVCRT_VERSION__) && (__MSVCRT_VERSION__ < 0x0800))
# define I64_FORMATA "%I64"
#else
# define I64_FORMATA "%ll"
#endif
#define VAL_FORMAT I64_FORMATA "u"
I can't speak for the free Borland compiler and runtime. I also don't know if it was your intention to support multiple Windows compilers since you merged from multiple sources.
>> typedef unsigned long long u_long_64;
You could use the same conditional compile above, or just use __int64. Not all windows compilers support long long. Most do (or can) support __int64. (MinGW defines __int64 as long long for instance).
>> bool gb_exit = 0;
Unsynchronized access (read & write) is "naughty" and should never be done (even if it "works" as it's being used here). A better way is to use a Win32 event:
Code:
HANDLE gev_exit = 0;
//...in main, create the event
gev_exit = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!gev_exit)
{
printf("CreateEvent failed, le = %d", GetLastError());
return 1;
}
//...in the thread, wait for the event and remove call to Sleep()
while(WaitForSingleObject(gev_exit, 1000) != WAIT_OBJECT_0)
{
printf("\b");
...
//...when you want the thread to exit
SetEvent(gev_exit);
Don't stop the thread from within semiprimegen(), it shouldn't have to know anything about it. Stop the thread within main() where it was created.
>> bool line_number_switch = 0
Suggestion: Use true and false with all bool types for readability and consistency.
>> _beginthread(progress_indicator, 0, NULL);
Check return, handle errors.
>> fpurge()
This is old, nonstandard, and doesn't do what fflush() does. I can't see any reason why you would use it on any platform.
>> primefile = fopen()
None of the file function calls are checking for errors.
>> if(line_number_switch==0)
Since this is done only once, move it outside the for loop and do it once unconditionally.
>> if(filecount==10)
Suggestion: A better variable name would be rowcount.
>> 100.0 * x / semiprimes_count
Suggestion: Using explicit parenthesis is generally considered more readable and safer. Being explicit about your intended order of operations (with parens) will prevent bugs in those cases where parens are really required and you forget to add them.
>> (int)(100.0 * x / semiprimes_count)
Drop the ".0", floating point math isn't needed since integer division will give the same results in this case.
>> #define BUFFER 1000000
"Magic number". Move this inside semiprimegen() as a constant.
const u_long_64 buff_sz = 1000000;
>> if(store_2)
Again, done only once, move outside the for loop. Or better, initialize buff_mult to 0 so that the initial allocation of primes_address is performed the same as for semi_prime_address in the next for loop.
>> (u_long_64*)malloc()
It's considered good practice not to cast the result of malloc/realloc in C.
http://c-faq.com/malloc/cast.html
>> *(primes_address + prime_count-1) = number_to_check;
Suggestion: Array subscript notation may be a little more readable. More so in other parts of the code.
primes_address[prime_count-1] = number_to_check;
Overall:
Everywhere I've worked, the coding standards didn't allow tabs in the source, and they didn't allow code or comments past the 80'th column. Something to consider.
There are 4 warnings due to conversion from u_long_64 to size_t. I would consider changing some "counters" to type size_t if you know they will never exceed 64 bits. If they ever do exceed 64 bits, then you'll have problems. Ensure your compilation options have all warning turned on. Get into the habbit of treating warnings as errors.
"x" is an unreferenced local in semiprimegen().
gg