store or check value of getenv() only once in a shared library/DLL - c

I have a function to print debug logs which has to be toggled depending on the environment variable. Instead of checking the env var each time the print_trace() is called, what should be the best method to store it and reuse that value?
void print_trace(const char* msg)
{
const char* s = getenv("DEBUG_TRACE");
if(!strcmp(s,"ON"))
printf(msg);
}
There is no main() as this is a shared library.

You could save the result of the decision in a static variable.
void print_trace(const char* msg)
{
static int debug_on = -1; // -1 == not yet set
if (debug_on == -1) {
const char* s = getenv("DEBUG_TRACE");
debug_on = s && (strcmp(s, "ON") == 0);
}
if(debug_on)
printf("%s", msg);
}

You could use the thread safe call_once feature that was added in C11.
Example:
#include <threads.h>
static bool debug_mode; // your debug mode flag
void set_debug_mode(void) { // this is only called once
const char *s = getenv("DEBUG_TRACE");
debug_mode = s && !strcmp(s, "ON");
}
void print_trace(const char* msg) {
static once_flag flag = ONCE_FLAG_INIT;
call_once(&flag, set_debug_mode); // called once to set debug_mode
if(debug_mode)
printf(msg);
}

Related

What is the use of privdata argument in redisAsyncCommand?

The function definition provided in the source for redisAsyncCommand( ) is:
static int __redisAsyncCommand(redisAsyncContext *ac, redisCallbackFn *fn, void *privdata, const char *cmd, size_t len) { ... }
What is the purpose of the void *privdata argument? In what cases would it be useful?
As I understand by reading the code on gihub, the purpose of privdata is to send your callback some predefined data (which can be anything; that is why void* is used). In your callback (fn pointer to redisCallbackFn) you will recieve that privdata as parameter (for example look at cb->fn(ac,reply,cb->privdata); in func __redisRunCallback file async.c)
For example (simplified pseudo code for something similar) is bellow. In this example there are 3 successive calls to __redisAsyncCommandSimplified and only one handler (callback). In callback I have used privdata to determine behavior of
callback. Your callback can also use that privdata data for something else (like parameter for another function call, logging, structure creation/population, etc)...
#include <stdio.h>
#include <string.h>
typedef void (*Callback)(int, void*);
int __redisAsyncCommandSimplified(Callback call, void* privdata) {
call(1, privdata);
return 1;
}
void myHandler(int status, void* privdata) {
char* str = (char*)privdata;
printf("%s = ", str);
if (strcmp (str, "john") == 0) {
printf("lennon");
}
else if (strcmp(str, "ringo") == 0) {
printf("star");
}
else if (strcmp(str, "ringo") == 0) {
printf("star");
}
else if (strcmp(str, "paul") == 0) {
printf("mccartney");
}
else if (strcmp(str, "george")) {
printf("harrison");
}
else {
printf("who?!?");
}
printf("\n");
}
int main()
{
char c[20];
strcpy(c, "john");
__redisAsyncCommandSimplified(myHandler, c);
strcpy(c, "paul");
__redisAsyncCommandSimplified(myHandler, c);
strcpy(c, "someone else");
__redisAsyncCommandSimplified(myHandler, c);
return 0;
}

Start of thread changes already set global variable

I have ran into very strange behavior of my code, the basic flow of code is
main () parses a file and sets global variables accordingly.. such as
int frame_size, version;
typedef struct//file parsing variables
{
int frame,
int version; } configuration;
***//the function init_parse calls***
static int handler(void* user, const char* section, const char* name,
const char* value)
{
configuration* pconfig = (configuration*)user;
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
if (MATCH("protocol", "version")) {
pconfig->version = atoi(value);
}
else if (MATCH("basic", "frames")) {
pconfig->frames= atoi(value);
frame_size=pconfig->frames;
}
else {
return 0; /* unknown section/name, error */
}
return 1;
}
main (){
configuration config;
if (ini_parse("test.ini", handler, &config) < 0) {
printf("Can't load 'test.ini'\n");
getchar();
iret = pthread_create(&hThread,NULL, pcapreader, NULL);
if(iret)
{
fprintf(stderr,"Error - pthread_create() return code: %d\n",iret);
exit(EXIT_FAILURE);
}
}
Now, the line followed by main()'s parsing line, everything seems set, but as soon as thread is started , the value frame_size changes to something 6345720:/
I have double checked code for possible replicated variable. thread only uses frame_size in for loop to check the limit.
the only problem was with initialization, once initialized, everything worked like a charm :)
I think it might never initialize the frame_size variable and never reached MATCH("basic", "frames") statement too.

Error in CloudPebble, "ld returned 1 exit status"

So, I'm trying to make a Pebble app that generates a random string when you press a button. I'm pretty sure I have the Pebble code right, but I'm not sure what to do with this error:
/sdk2/[long stuff here]/ In function `_sbrk_r':
/home/[more long stuff]: undefined reference to `_sbrk'
collect2: error: ld returned 1 exit status
Waf: Leaving directory `/tmp/tmpX94xY7/build'
Build failed
And here's my code:
#include <pebble.h>
#include <stdlib.h>
#include <stdio.h>
Window *window;
TextLayer *text_layer;
char* one[] = {"string1", "stringone", "stringuno"};
char* two[] = {"string2", "stringtwo", "stringdos"};
char* three[] = {"string3", "stringthree", "stringtres"};
char* four[] = {"string4", "stringfour", "stringcuatro"};
int length1 = sizeof(one)/sizeof(*one);
int length2 = sizeof(two)/sizeof(*two);
int length3 = sizeof(three)/sizeof(*three);
int length4 = sizeof(four)/sizeof(*four);
char* gen()
{
char out[256];
sprintf(out, "%s, and then %s %s %s.", one[rand() % length1], two[rand() % length2], three[rand() % length3], four[rand() % length4]);
char* result = malloc(strlen(out) + 1);
strcpy(result, out);
return result;
}
static void select_click_handler(ClickRecognizerRef recognizer, void *context)
{
char* stringGen = gen();
text_layer_set_text(text_layer, stringGen);
free(stringGen);
}
static void click_config_provider(void *context)
{
window_single_click_subscribe(BUTTON_ID_SELECT, select_click_handler);
window_single_click_subscribe(BUTTON_ID_UP, select_click_handler);
window_single_click_subscribe(BUTTON_ID_DOWN, select_click_handler);
}
static void window_load(Window *window)
{
Layer *window_layer = window_get_root_layer(window);
GRect bounds = layer_get_bounds(window_layer);
text_layer = text_layer_create((GRect) { .origin = { 0, 72 }, .size = { bounds.size.w, bounds.size.h } });
text_layer_set_text(text_layer, "Press >>>");
text_layer_set_text_alignment(text_layer, GTextAlignmentCenter);
layer_add_child(window_layer, text_layer_get_layer(text_layer));
}
static void window_unload(Window *window)
{
text_layer_destroy(text_layer);
}
void handle_init(void)
{
window = window_create();
window_set_click_config_provider(window, click_config_provider);
window_set_window_handlers(window, (WindowHandlers) {
.load = window_load,
.unload = window_unload,
});
const bool animated = true;
window_stack_push(window, animated);
}
void handle_deinit(void)
{
text_layer_destroy(text_layer);
window_destroy(window);
}
int main(void)
{
handle_init();
app_event_loop();
handle_deinit();
}
I can't figure out why I'm getting that error. It's a simple application, I just have these little tweaks.
Thank you in advance for your help!
According to this (old) FAQ, that error happens when you try to use a C standard library function that hasn't been implemented in the SDK. If you look in the API reference, snprintf is available, but not sprintf. You can replace your call to sprintf in gen with something like
snprintf(out, 256, "%s, and then %s %s %s.", one[rand() % length1], two[rand() % length2], three[rand() % length3], four[rand() % length4]);
I just tried this out and it builds fine.
(As an aside, it may be a better a idea to declare out a global static buffer and just write over it each time, instead of constantly dynamically allocating memory.)

"called object is not a function" error - C

int getSpeedOfMotorInPercent(int RPM)
{
int speedOfMotor = (RPM/5000.0)*100;
return speedOfMotor;
}
static char *test_GetSpeedOfMotor(int speedInPercent)
{
mu_assert("error, RPM != 70%", speedInPercent == 70);
return 0;
}
static char *run_all_tests(int RPM)
{
mu_run_test(test_GetSpeedOfMotor(RPM));
return 0;
}
I get the error "called object is not a function" on mu_run_test(test_GetSpeedOfMotor(RPM));
I tried removing the pointer of the function but then I get even more errors.
EDIT:
#define mu_assert(message, test) do { if (!(test)) return message; } while (0)
#define mu_run_test(test) do { char *message = test(); tests_run++; if (message) return message; } while (0)
extern int tests_run;
this is the mu_run_test function. It is provided to me like that in the header file.
You're passing test_GetSpeedOfMotor(RPM) as test in the macro, which will result in this code:
char *message = test_GetSpeedOfMotor(RPM)();
Since you're probably using a test framework which you don't want to change, just remove the RPM parameter from the declaration of test_GetSpeedOfMotor function and use it like this:
int testRpmInPercent;
static char *test_GetSpeedOfMotor()
{
mu_assert("error, RPM != 70%", testRpmInPercent == 70);
return 0;
}
static char *run_all_tests(int RPM)
{
testRpmInPercent = RPM;
mu_run_test(test_GetSpeedOfMotor);
return 0;
}
Then you'll have to find an other way of sharing the RPM value with the test function. Like a global variable or with whatever method the test framework has to offer.
If you're willing to change the test framework, I would modify that define to this (remove () after test):
#define mu_run_test(test) do { char *message = test; tests_run++; if (message) return message; } while (0)

What does the usage of `(void)struct_pointer`?

I am now reading a project and find some of the codes hard to understand, like below:
struct mcachefs_metadata_t* mdata_root;
...
mcachefs_metadata_release(mdata_root);
And the definition of mcachefs_metadata_release is as below:
void
mcachefs_metadata_release(struct mcachefs_metadata_t* mdata)
{
(void) mdata;
mcachefs_metadata_unlock ();
}
And the definitioin of mcachefs_metadata_unlock is as below:
#define mcachefs_metadata_unlock() mcachefs_mutex_unlock ( &mcachefs_metadata_mutex, "metadata", __CONTEXT );
Then, the mcachefs_mutex_unlock function:
void
mcachefs_mutex_unlock(struct mcachefs_mutex_t* mutex, const char* name,
const char* context)
{
int res;
...
mutex->owner = 0;
mutex->context = NULL;
res = pthread_mutex_unlock(&(mutex->mutex));
if (res == 0)
{
return;
}
...
}
I could not understand what does the (void) mdata; mean in the
mcachefs_metadata_release function. What does the usage of it?
It's for suppressing unused argument: mdata compiler warnings. Rather bad practice, by the way.

Resources