#define directive question - c

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.

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.

The ebpf program(sockops) does not take effective when attaching into a child cgroup

I wrote an ebpf code to set tos of ip header, it take effective when attaching into the root path (1/sys/fs/cgroup/unified1), but it does not take effective when attaching into the child cgroup such as /sys/fs/cgroup/unified/docker/
code:
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ip.h>
#include <linux/in.h>
#include <linux/socket.h>
#include "bpf_helpers.h"
//#ifndef __section
//# define __section(NAME) \
// __attribute__((section(NAME), used))
//#endif
//
#ifndef BPF_FUNC
#define BPF_FUNC(NAME, ...) \
(*NAME)(__VA_ARGS__) = (void *) BPF_FUNC_##NAME
#endif
static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);
#ifndef printk
# define printk(fmt, ...) \
({ \
char ____fmt[] = fmt; \
trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
})
#endif
SEC("sockops")
int set_initial_rto(struct bpf_sock_ops *skops)
{
int tos = 0x38;
int op = (int) skops->op;
printk("remote %x, op=%d tos %d\n",skops->remote_ip4, op,tos);
switch (op) {
case BPF_SOCK_OPS_TCP_CONNECT_CB:
case BPF_SOCK_OPS_ACTIVE_ESTABLISHED_CB:
case BPF_SOCK_OPS_PASSIVE_ESTABLISHED_CB:
printk("set tos %d",tos);
bpf_setsockopt(skops,IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
break;
}
return 1;
}
char _license[] SEC("license") = "GPL";
Server env:
Ubuntu
kernel version : 5.4.0-77
bpf status:
# bpftool cgroup tree
CgroupPath
ID AttachType AttachFlags Name
/sys/fs/cgroup/unified/docker
10544 sock_ops set_tos
expected:
I can capture the package by tcpdump
actually:
tcpdump can't capture any package with DSCP mark
$ sudo tcpdump -vv -n ip -c 10 -i bond0.1000 and ip[1]=56
tcpdump: listening on bond0.1000, link-type EN10MB (Ethernet), capture size 262144 bytes
BTW, tcpdump can capture the package with DSCP mark if I attach the bpf prog to /sys/fs/cgroup/unified/

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.

ffmpeg transcode and avfilter error

FFmpeg configure options:
--enable-avfilter \
--enable-nonfree \
--disable-filters \
--enable-filter=movie \
--enable-filter=overlay \
--enable-filter=null \
--enable-filter=anull \
--enable-filter=scale \
--enable-filter=rotate \
and run success use
filter_spec = "null"; /* passthrough (dummy) filter for video */
and get the transcoding video success!
but use
filter_spec = "movie=/storage/emulated/0/image.png [wm]; [in][wm] overlay=10:10 [out]";
then run to
if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec,
&inputs, &outputs, NULL)) < 0)
goto end;
get the error:
Invalid data found when processing input
please help me...

Compile time check with C preprocessor directives

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

Resources