Compile time check with C preprocessor directives - c

Is there a way to make the log-level checking in my LOGGING-macro (shown below) to happen during compile-time? It should be possible as it is already known during compile time whether the condition (if (pLogLevel <= LOG_LEVEL)) is true or false. Here is an example of how the macro could be used:
LOGGING(LOG_DEBUG, "FALSE - Wrong Marker\n");
Originally I thought that #ifdirectives within a #define could help me, but this article showed me that this would not be possible. This is the source code to my problem:
#ifndef __LOGGING_H__
#define __LOGGING_H__ 1
#include <time.h>
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERROR 3
#define LOG_WARN 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
#define LOG_NONE 8
/* set the global logging level here */
#define LOG_LEVEL LOG_INFO
void print_timestamp(void);
#if LOG_LEVEL == LOG_DEBUG
#define _LOG_PREAMBLE \
fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
#else
#define _LOG_PREAMBLE \
print_timestamp();
#endif
#if LOG_LEVEL == LOG_EMERG
#define _LOG_LEVEL fprintf(stdout, "EMERG ");
#elif LOG_LEVEL == LOG_ALERT
#define _LOG_LEVEL fprintf(stdout, "ALERT ");
#elif LOG_LEVEL == LOG_CRIT
#define _LOG_LEVEL fprintf(stdout, "CRIT ");
#elif LOG_LEVEL == LOG_ERROR
#define _LOG_LEVEL fprintf(stdout, "ERROR ");
#elif LOG_LEVEL == LOG_WARN
#define _LOG_LEVEL fprintf(stdout, "WARN ");
#elif LOG_LEVEL == LOG_NOTICE
#define _LOG_LEVEL fprintf(stdout, "NOTICE ");
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "INFO ");
#elif LOG_LEVEL == LOG_INFO
#define _LOG_LEVEL fprintf(stdout, "DEBUG ");
#else
#define _LOG_LEVEL
#endif
#define LOGGING(pLogLevel, ...) \
/* change this to compile time conditional if possible */ \
if (pLogLevel <= LOG_LEVEL) \
{ \
_LOG_PREAMBLE \
_LOG_LEVEL \
fprintf(stdout, ##__VA_ARGS__); \
}
#endif /* __LOGGING_H__ */

One approach would be to combine the log level into the logging macro.
This would create a set of macros that would be turned on or off depending on the log level.
You would use these macros and they would appear or not depending on the log level at the time of the compile. So they would be used like the following.
LOGGING_LEVEL_DEBUG("a Debug log.");
//.... some code
LOGGING_LEVEL_EMERG("a Emerge log.");
So the macros definitions would look something like the following:
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERROR 3
#define LOG_WARN 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
#define LOG_NONE 8
/* set the global logging level here */
#define LOG_LEVEL LOG_INFO
void print_timestamp(void);
#if LOG_LEVEL >= LOG_DEBUG
#define _LOG_PREAMBLE \
fprintf(stdout, "%s:%d ", __FILE__, __LINE__);
#else
#define _LOG_PREAMBLE \
print_timestamp();
#endif
#if LOG_LEVEL >= LOG_EMERG
#define LOGGING_LEVEL_EMERG(...) \
{ \
_LOG_PREAMBLE \
fprintf(stdout, "EMERG "); \
fprintf(stdout, ##__VA_ARGS__); \
}
#else
#define LOGGING_LEVEL_EMERG(...)
#endif
#if LOG_LEVEL >= LOG_ALERT
#define LOGGING_LEVEL_ALERT(...) \
{ \
_LOG_PREAMBLE \
fprintf(stdout, "ALERT "); \
fprintf(stdout, ##__VA_ARGS__); \
}
#else
#define LOGGING_LEVEL_ALERT(...)
#endif

You could define the macros themselves conditionally:
#if LOG_LEVEL > 0
# define LOG(...) printf(__VA_ARGS__)
#else
# define LOG(...)
#endif
#if LOG_LEVEL > 1
// and so forth

Related

Multiple definition of function error wont go away

I have a project with many files and they all include one header called logging.h, I dont know what happened but for some reason when i try to compile this happens. I can not revert the changes and I dont know what to do.
These lines repeat themselves multiple times
/usr/bin/ld: fs/operations.o: in function `send_request':
/root/so/mbroker/utils/logging.h:59: multiple definition of `send_request'; mbroker/mbroker.o:/root/so/mbroker/utils/logging.h:59: first defined here
/usr/bin/ld: fs/operations.o: in function `serialize':
/root/so/mbroker/utils/logging.h:68: multiple definition of `serialize'; mbroker/mbroker.o:/root/so/mbroker/utils/logging.h:68: first defined here
/usr/bin/ld: fs/state.o: in function `clear_session':
/root/so/mbroker/utils/logging.h:53: multiple definition of `clear_session'; mbroker/mbroker.o:/root/so/mbroker/utils/logging.h:53: first defined here
As you can see it's all happening in logging.h
Here's my logging.h
#ifndef __UTILS_LOGGING_H__
#define __UTILS_LOGGING_H__
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h> //open
#include <fcntl.h> //flags for open
#include <unistd.h>
#define PIPENAME 256
#define BOXNAME 32
#define MSIZE 256
#define COMMAND 8
static const __uint8_t REGISTER_PUBLISHER = 1;
static const __uint8_t REGISTER_SUBSCRIBER = 2;
static const __uint8_t CREATE_BOX = 3;
static const __uint8_t REMOVE_BOX = 5;
static const __uint8_t LIST_BOX = 7;
static const char INVALID_SESSIONS[] = "Invalid number of sessions";
static const char PIPENAME_TOO_BIG[] = "The pipe's name has too many characters";
static const char INVALID_BOXNAME[] = "The box's name is invalid";
static const char INVALID_NUMBER_OF_ARGUMENTS[] = "Insufficient or too many arguments";
static const char INVALID_ARGUMENTS[] = "One of the arguments is invalid";
static const char UNEXISTENT_PIPE[] = "Pipe doesn't exist";
static const char EXISTENT_PIPE[] = "Pipe already exists";
static const char ERROR_WRITING_PIPE[] = "Error writing to pipe";
static const char SIGNAL_FAIL[] ="Failed to initialize signals";
typedef struct box{
char boxname[BOXNAME];
int hasWriter;
int n_readers;
struct box *next;
} box;
typedef struct req{
int _code;
char _client_pipe[PIPENAME];
char _box_name[BOXNAME];
} request;
typedef enum {
LOG_QUIET = 0,
LOG_NORMAL = 1,
LOG_VERBOSE = 2,
} log_level_t;
//deletes fifo
void clear_session(int fd, char* fn){
close(fd);
unlink(fn);
}
/*writes to pipe tx a pointer with information*/
void send_request(int tx, request *r1) {
ssize_t ret = write(tx, &r1, sizeof(r1));
if (ret < 0) {
fprintf(stdout, "ERROR: %s\n", ERROR_WRITING_PIPE);
exit(EXIT_FAILURE);
}
}
/*Returns a pointer to a struct containing the request*/
request *serialize(int code, char* client_pipe, char* box_name){
request *r1 = (request*) malloc(sizeof(request));
r1->_code = code;
strcpy(r1->_client_pipe, client_pipe);
strcpy(r1->_box_name, box_name);
return r1;
}
void sig_handler(int sig);
void set_log_level(log_level_t level);
extern log_level_t g_level;
#define INFO(...) \
do { \
char buf[2048]; \
snprintf(buf, 2048, __VA_ARGS__); \
fprintf(stderr, "[INFO]: %s:%d :: %s :: %s\n", __FILE__, __LINE__, \
__func__, buf); \
} while (0);
#define PANIC(...) \
do { \
char buf[2048]; \
snprintf(buf, 2048, __VA_ARGS__); \
fprintf(stderr, "[PANIC]: %s:%d :: %s :: %s\n", __FILE__, __LINE__, \
__func__, buf); \
exit(EXIT_FAILURE); \
} while (0);
#define WARN(...) \
do { \
if (g_level == LOG_NORMAL || g_level == LOG_VERBOSE) { \
char buf[2048]; \
snprintf(buf, 2048, __VA_ARGS__); \
fprintf(stderr, "[WARN]: %s:%d :: %s :: %s\n", __FILE__, \
__LINE__, __func__, buf); \
} \
} while (0);
#define LOG(...) \
do { \
if (g_level == LOG_NORMAL || g_level == LOG_VERBOSE) { \
char buf[2048]; \
snprintf(buf, 2048, __VA_ARGS__); \
fprintf(stderr, "[LOG]: %s:%d :: %s :: %s\n", __FILE__, \
__LINE__, __func__, buf); \
} \
} while (0);
#define DEBUG(...) \
do { \
if (g_level == LOG_VERBOSE) { \
char buf[2048]; \
snprintf(buf, 2048, __VA_ARGS__); \
fprintf(stderr, "[DEBUG]: %s:%d :: %s :: %s\n", __FILE__, \
__LINE__, __func__, buf); \
} \
} while (0);
#endif // __UTILS_LOGGING_H__
I tried deleting files, going back as far as i could but this error wont stop haunting me.
I also tried make clean multiple times, but did nothing either.
I went back to an old backup of the project which was ok and now it's showing me this same error message again. I tried compiling both through vsc and through wsl.
Now that i think it through, the error might have started when i included .c in another file. I have long deleted that include line but am still getting the errors.
The solution involved only writing prototypes on the header and implementing the functions in a logging.c. It's weird the compiler only warned me after like many and many trials, but it's solved and that's all i could ask for.

Convert <netinet/in.h> protocols to names?

There is a long list of protocols defined in <netinet/in.h>:
/*
* Protocols (RFC 1700)
*/
#define IPPROTO_IP 0 /* dummy for IP */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define IPPROTO_HOPOPTS 0 /* IP6 hop-by-hop options */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define IPPROTO_ICMP 1 /* control message protocol */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define IPPROTO_IGMP 2 /* group mgmt protocol */
#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */
#define IPPROTO_IPV4 4 /* IPv4 encapsulation */
#define IPPROTO_IPIP IPPROTO_IPV4 /* for compatibility */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define IPPROTO_TCP 6 /* tcp */
#if !defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE)
#define IPPROTO_ST 7 /* Stream protocol II */
/* ... */
Is there a default function/call to translate protocols defined in <netinet/in.h> to names? Ideal to have chars[] in return:
ipproto2str(IPPROTO_ICMP): "Control Message Protocol (ICMP)"
You're looking for getprotobynumber().
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
int main(void) {
struct protoent *p = getprotobynumber(IPPROTO_ICMP);
if (p) {
printf("IPPROTO_ICMP (%d) = %s\n", p->p_proto, p->p_name);
} else {
puts("Couldn't find IPPROTO_ICMP");
}
}

How to evaluate part of an expression using macros in C?

I am currently developing a unit test library in C and I wanted to add a functionality Catch (in C++) had.
When you do, using Catch :
int x = 5;
REQUIRE(x == 4);
The output will be something like this :
Failed statement : x == 4
evaluated as 5 == 4
Is it possible to do something like that in C ?
This needs to be done at runtime.
You could do something like this. It's not very convenient, but it works:
#include <stdio.h>
#include <stdlib.h>
#define ASSERT_INT 1
#define ASSERT_EQ(x,y,type) do { if((x)!=(y)) { \
switch(type) { \
case ASSERT_INT: \
printf("Failed statement : %s == %d\n\tevaluated as %d == %d\n", \
#x, (y),(x), (y)); break; \
} exit(EXIT_FAILURE); }} while(0)
It requires some work though. If you want many operations you can do like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ASSERT_INT 1
#define ASSERT_EQ 1
#define ASSERT(x,y,op,type) do { \
int success; \
char op_str[3]; \
switch(op) { \
case ASSERT_EQ: \
strcpy(op_str, "==");success = ((x) == (y)); break; \
} \
if(!success) { \
switch(type) { \
case ASSERT_INT: \
printf("Failed statement : %s %s %d\n\tevaluated as %d %s %d\n", \
#x, op_str, (y),(x), op_str, (y)); break; \
} exit(EXIT_FAILURE); }} while(0)
And the output:
$ ./a.out
Failed statement : x == 4
evaluated as 5 == 4
You will need to add a modified version of strcpy(op_str, "==");success = ((x) == (y)); break; for each different logical operation and a modified version of printf("Failed statement : %s %s %d\n\tevaluated as %d %s %d\n", #x, op_str, (y),(x), op_str, (y)); break; for each different type.

'asm' or '__attribute__' before 'int'

I am getting the error below while doing Linux migration. Line no 25 from the file is below. Please suggest, added my_val.h
In file included from ddtc.c:36:
ddtc.h:25: error: expected '=', ',', ';', 'asm' or '__attribute__' before 'int'
make: *** [ddtc.o] Error 1
ddtc.h
18 #pragma ident "$Id: ddtc.h 2 28-JUN-2014 09:31:15 DDAC$"
19
20 #ifndef _INCL_STRING_FDS_
21 #define _INCL_STRING_FDS_
22
23 #include "my_val.h"
24
25 int stringFDS(char ** s, char * myVar); /* String feeder*/
26
27 #endif
my_val.h
#ifndef _TYPE_VALUE_INC_
#define _TYPE_VALUE_INC_
/* Return value */
#ifndef RETURN_PASS
#define RETURN_PASS 0
#endif
#ifndef RETURN_DENY
#define RETURN_DENY -1
#endif
#define RETURN_EOF 1 /* Processing done due to EOF */
#ifndef WIN32
#ifndef TYPEDEF_BOOL_FOR_C
#define TYPEDEF_BOOL_FOR_C
#ifndef bool
typedef int bool
#endif
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#endif /* ndefined TYPEDEF_BOOL_FOR_C */
#endif /* ndefined WIN32 */
#endif /* ndefined _TYPE_VALUE_INC_ */

#define directive question

I've got the following code:
#define checkLiteMessage \
{ \
#ifdef LITE_VERSION \
if (alertView.tag == 100) \
{ \
if (buttonIndex == 1) \
[ [UIApplication sharedApplication] openURL: buyAppLink]; \
[alertView release]; \
return; \
} \
#endif \
} \
What I want to do is to have the following code to be included every time I call checkLiteMessage:
#ifdef LITE_VERSION
if (alertView.tag == 100)
{
if (buttonIndex == 1)
[ [UIApplication sharedApplication] openURL: buyAppLink];
[alertView release];
return;
}
#endif
What's my problem? Why doesn't this code compile?
Thanks.
You've specified the macro with line continuations, which is correct. However, that means the #ifdef statement is not at the start of the line, so the preprocessor isn't going to do it.
You can't have the #ifdef embedded inside the macro. You could reverse that:
#ifdef LITE_VERSION
#define checkLiteMessage do { \
if (alertView.tag == 100) \
{ \
if (buttonIndex == 1) \
[ [UIApplication sharedApplication] openURL: buyAppLink]; \
[alertView release]; \
return; \
} \
} while(0)
#else
#define checkLiteMessage do { ; } while (0)
#endif
I'll add that putting a 'return' statement inside a macro is pretty evil and will be confusing to everyone. Don't do it.
The problem is that you cannot include preprocessor directives in a macro.
You may want to do that instead :
#ifdef LITE_VERSION
#define checkLiteMessage \
{ \
if (alertView.tag == 100) \
{ \
if (buttonIndex == 1) \
[ [UIApplication sharedApplication] openURL: buyAppLink]; \
[alertView release]; \
return; \
} \
}
#else
#define checkLiteMessage
#endif
Also make sure that the "return" line does what you think it does (here, it exits the function calling checkLiteMessage, not just the macro (a macro cannot be "exited").
The the backslash-linefeed combination is equivalent to no letters at all so
#define x y \
z
is equivalent to
#define x y z
Also, according to the standard, preprocessor directives in a macro body are not expanded or interpreted and that #ifdef is passed to the compiler instead of conditionally dropping the code in between.
You may inspect this behaviour creating a file a.c with the contents
#define x y \
z
#define v \
#ifdef E
x
v
and preprocessing it with the command gcc -E a.c.
In your situation, what you need to do is
#ifdef LITE_VERSION
#define checkLiteMessage \
{ \
if (alertView.tag == 100) \
{ \
if (buttonIndex == 1) \
[ [UIApplication sharedApplication] openURL: buyAppLink]; \
[alertView release]; \
return; \
} \
}
#else
#define checkLiteMessage
#endif
The preprocessor is one-pass only. So the sequence #ifdef is getting to your compiler, causing an error. Make it a function.

Resources