How the assignment operator in container_of() macro is working - c

I have tried to work with the container_of macro in linux kernel.
what I get by google is as follow
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#define container_of(ptr, type, member) \
({ const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
#define CONT(prt, type, mem) container_of((prt), type, mem)
struct test {
int a;
};
struct m {
int b;
struct test t;
int c;
};
int main(int argc, char *argv[])
{
/* existing structure */
struct m *ma;
ma = malloc(sizeof(struct m));
ma->t.a = 5;
ma->b = 3;
/* pointer to existing entry */
struct test *te = &ma->t;
struct m *m = CONT(te, struct m, t);
printf("m->b = %d\n", m->b);
return EXIT_SUCCESS;
}
o/p
m->b = 3
but I am having the doubt in the assignment of *m .I have tried following
#include <stdio.h>
int main()
{
int x = (int k = 9;k-2;);
printf("x= %d k = %d",x,k);
}
o/p
one.c:5: error: expected ‘)’ before ‘k’
one.c:5: error: expected expression before ‘;’ token
one.c:6: error: ‘k’ undeclared (first use in this function)
one.c:6: error: (Each undeclared identifier is reported only once
one.c:6: error: for each function it appears in.)
If this assignment is wrong here then how it is working in container of macro.what is the difference in above two.(I know one is macro and other is normal declaration but after macro expansion both will look same)
Note:Excuse me as this may be a simple but I am not able to figure it out.
kinldy give some solution to my dobut.

This is using special gcc features, namely block expressions ({ }). These allow to to have a object definition inside an expression. The last statement in this construct determines the value of the block expression.
So you missed the additional { } inside the expression for your test case.
Also:
there is no assignment in that macro, but only initialization of the local variable
the typeof operator in there also is a gcc extension

I am adding my answer to this question because I got some point .It may help other.
#include <stdio.h>
int main()
{
int x = ({int k = 9;k-2;});
printf("x = %d",x);
}
o/p
x = 7
As Jens said above its all true I have missed the { } but addition to that ,I am printing the value of k which is not correct as all the value created with in the ({ }) are temporary and will delete as soon as the value of expression is evaluated.
http://gcc.gnu.org/onlinedocs/gcc/Statement-Exprs.html#Statement-Exprs

Related

Why do C macros act as pointers even though I am not passing variables by pointer

I am trying to write a series of C macros to provide some generic data type capability for a struct, or grouping of structs that manages a dynamically allocated array. At this point I have written several structs for each data type and am just starting to write a Macro function that can initialize the struct variables and allocated a user defined amount of memory. The idea is to create one init function that can initialize any type of struct, so as long as it has the write form. For this implementation I first have to instantiate a copy of the struct, which is then passed to the macro. The macro ensures that the variables allocated_length and active_length is of type size_t. Then it determines the type of array by de-referencing it and using thetypeof operator. Finally it allocates memory to ptr and then checks to ensure the allocation was not returned as NULL. However, in this example, I do not pass anything back to the main program, and I am not passing variables as a pointer. Yet, somehow, the struct in the structs in the main program are able to see the modifications I made in the Macro. How is this?
#define init_vector(vec_struct, aloc_length) ({size_t _a = (aloc_length); \
size_t _b = 0; \
typeof(vec_struct.array) ptr = malloc(aloc_length * sizeof(&vec_struct.array)); \
if (ptr == NULL) { \
perror("WARNING: "); \
exit(0); \
} \
vec_struct.allocated_length = _a; \
vec_struct.active_length = _b; \
vec_struct.array = ptr; \
})
typedef struct
{
int *array;
size_t allocated_length;
size_t active_length;
} IntVector;
typedef struct
{
float *array;
size_t allocated_length;
size_t active_length;
} FltVector;
int main() {
IntVector int_vec;
init_vector(int_vec, 30);
printf("%ld\n", int_vec.allocated_length);
FltVector float_vec;
init_vector(float_vec, 20);
printf("%ld\n", float_vec.allocated_length);
return 0;
}
You need to understand that macros are not functions. They simply replace text (or more precise tokens) before the actual C compilation starts.
The compiler will compile this code:
int main() {
IntVector int_vec;
({size_t _a = (30); size_t _b = 0; typeof(int_vec.array) ptr = malloc(30 * sizeof(&int_vec.array)); if (ptr ==
# 32 "/app/example.c" 3 4
((void *)0)
# 32 "/app/example.c"
) { perror("WARNING: "); exit(0); } int_vec.allocated_length = _a; int_vec.active_length = _b; int_vec.array = ptr; });
printf("%ld\n", int_vec.allocated_length);
FltVector float_vec;
({size_t _a = (20); size_t _b = 0; typeof(float_vec.array) ptr = malloc(20 * sizeof(&float_vec.array)); if (ptr ==
# 36 "/app/example.c" 3 4
((void *)0)
# 36 "/app/example.c"
) { perror("WARNING: "); exit(0); } float_vec.allocated_length = _a; float_vec.active_length = _b; float_vec.array = ptr; });
printf("%ld\n", float_vec.allocated_length);
return 0;
}
https://godbolt.org/z/ezvKfdn33
Is it something you have expected?
Macros have to be used with great caution and as little as possible.
From https://en.cppreference.com/w/c/preprocessor/replace:
Function-like macros
#define identifier( parameters ) replacement-list
Function-like macros replace each occurrence of a defined identifier with replacement-list, additionally taking a number of arguments, which then replace corresponding occurrences of any of the parameters in the replacement-list.
The syntax of a function-like macro invocation is similar to the syntax of a function call: each instance of the macro name followed by a ( as the next preprocessing token introduces the sequence of tokens that is replaced by the replacement-list. The sequence is terminated by the matching ) token, skipping intervening matched pairs of left and right parentheses.
...
That means (based on your example) that every occurrence of the identifier init_vector is replaced with the code after the last parentheses of the parameter list.
And each occurrence of the parameters vec_struct, aloc_length will also replaced accordingly.
At the end, it is not about functions and function calls, but replacement.
"The preprocessor supports text macro replacement and function-like text macro replacement."

Conversion to non-scalar error inside macro in C

I have the following test code in C:
#include <stdio.h>
#include <stdlib.h>
typedef struct test {
int a;
int b;
} test_t;
#define test_init(test, a) \
test = (test_t)calloc(1, sizeof(test_t)); \
(test)->a = a; \
(test)->b = (test)->a + 1; \
int main()
{
test_t test;
int a = 5;
test_init(&test, a);
return 0;
}
But it throws the following error:
error: conversion to non-scalar type requested
Why exactly dos this happen? Please note that the discussion is not here whether to use an actual function or a macro. Let's just assume we are interested in macros. Why is the above error thrown, and what is the proper way to handle it?
Recall that function-like macros perform a direct substitution of their parameters. That means this:
test_init(&test, a);
Gets converted by the preprocessor into:
&test = (test_t)calloc(1, sizeof(test_t));
(&test)->a = a;
(&test)->b = (&test)->a + 1;
Note that in the first line you're attempting to assign something to &test. The result of the & operator does not result in an lvalue. That means you can't assign something to &test because it doesn't represent something you can assign to.
To fix this, you need to declare test in main as a pointer:
test_t *test;
int a = 5;
test_init(test, a);
Or, if you expect the macro to be passed an instance of type test_t, you don't need the call to calloc:
#define test_init(test, a) \
(test).a = a; \
(test).b = (test).a + 1; \

Is it possible to implement GNU C's typeof(x) with C11's _Generic?

To make some code compile in C and C++ I use this in a few places:
#ifdef __cplusplus
#define typeof(x) decltype(x) // works ok in most cases, except C++ reference types
#endif
char* a = (typeof(a)) malloc(4);
In C, this compiles to char* a = (char *) malloc(4) where the cast is totally unecessary, but in C++ void * is not implicitly promoted to char * and an error is issued if a cast is not present.
This is just as well when I can compile with -std=gnu11 on GCC or Clang, but what when I want to make my code compile as ISO C11? I thought I could use C11's _Generic to implement typeof(x) to cast some types:
#define gettype(x) _Generic((x), \
short: (short ), \
char: (char ), \
char*: (char *), \
default: (void *) )
int main (void) {
short a = (gettype(a)) 1;
return a;
}
But no matter what type defined in gettype(x) is given in a's declaration,
typeof.h: In function ‘main’:
typeof.h:2:24: error: expected expression before ‘,’ token
short: (short ), \
^
typeof.h:8:13: note: in expansion of macro ‘gettype’
char a = (gettype(a)) 1;
^~~~~~~
typeof.h:8:25: error: expected ‘,’ or ‘;’ before numeric constant
char a = (gettype(a)) 1;
gcc -E says that line expands just fine:
short a = (_Generic((a), short: (short ), char: (char ), char*: (char *), default: (void *) )) 1; ^
Is there some syntax I am missing, or is it simply not possible in C to generate cast code using _Generic?
The problem is that you can't have a partial expression inside the generic selection. A possible work-around could be to put a full expression inside it:
#define cast(from, to) _Generic((from), \
short: (short) (to), \
char: (char) (to), \
char*: (char*) (to), \
default: (void*) (to))
int main (void) {
short a = cast(a, 1);
return 0;
}
No, it's not possible. (Now watch someone prove me wrong!)
In a _Generic expression, each generic-association is either
type-name : assignment-expression
or
default : assignment-expression
It can't be a type name or something that expands to a type name. In particular, though a _Generic expression is resolved at compile time, it is not a macro. The final result is always an expression.
And I don't believe there's any other way to do what you want in standard C.
I just figured out..if Visual C++, in C, not C++, if you have two unrelated non-void pointer result types in a ternary expression, the type of the ternary expression is the first.
This can be useful.
So, in a corner I am painted into where I have a bunch of C code, I need to cast a void* to the type of something else, within a macro, that should not double evaluate...
typedef struct DesiredType { ... } DesiredType;
typedef struct ArbitraryType { ... } ArbitraryType;
ArbitraryType/*void*/* function_to_void_double_eval (void* a)
{
...
}
#if defined(_MSC_VER) && !defined(__cplusplus)
#define MACRO(x) (0 ? (DesiredType*)0 : function_to_avoid_double_eval(x))
#else // assume gcc
use typeof and temporaries in a macro
#endif

Use of pasting operator `##` with types in C

Is it possible to define a macro for the C preprocessor which takes an array as argument and expands to <type of array elements>_string? For example if x in an array of integers the macro invoked with argument x should expand to int_string.
I tried with
#define TypePaste(array) typeof(array[0])##_string
but it expands to )_string.
Even using multiple levels of indirection for the ## operand the macro doesn't expand correctly.
That's not possible. At the translation phase (the preprocessing phase) where macros are expanded and tokens are concatenated, the compiler (at this point, the preprocessor) does not yet have the notion of a type and thus cannot possibly generate types.
It is not all that clear what problem you are trying to solve, but given your comment:
the macro should expand to the name of an existing function. I'd like to define a function <type>_string for every existing type and then use the macro to select the right function according to the type of the array given.
Then you could use the C11 _Generic keyword:
#include <stdio.h>
void int_string (size_t size, int array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
void float_string (size_t size, float array[size])
{
printf("I am %s, do stuff here.\n", __func__);
}
#define TypePaste(array) \
_Generic( array, \
int: int_string, \
float: float_string ) \
(sizeof(array)/sizeof(*array), array) // function parameters
int main()
{
int i_arr[5];
float f_arr[3];
TypePaste(i_arr);
TypePaste(f_arr);
}
Output:
I am int_string, do stuff here.
I am float_string, do stuff here.
Note: this assumes that the passed parameter is a local/file scope allocated array. If passing a pointer, there's no type safety and the program will fail.
C11's _Generic type selection is the "proper" way to do what you want. There are other, platform dependent solutions, tough.
If you are using gcc – you don't say so eplicitly, but you use gcc's extension typeof already – you can use gcc's statement expresions and nested functions to create a comparison function for qsort on the spot:
double a[5] = {8.4, 8.1, 9.3, 12.2, 5.2};
qsort(a, 5, sizeof(*a), ({
int cmp(const void *p, const void *q) {
const typeof(a[0]) *pp = p;
const typeof(a[0]) *qq = q;
return (*pp < *qq) ? -1 : (*pp > *qq);
}
cmp;
}));
This creates a function and returns its address. (The last statement of a compound expression is its value. The scope of the local variables is the statement expression, but a nested function is not created on the stack so its safe to return a pointer to that function.)
For primitive types, where you want to sort according to the comparison operators < and >, you can turn that into a macro:
#define COMPARE(ARRAY)({ \
int cmp(const void *p, const void *q) { \
const typeof(ARRAY[0]) *pp = p; \
const typeof(ARRAY[0]) *qq = q; \
return (*pp < *qq) ? -1 : (*pp > *qq); \
} \
cmp; \
})
qsort(a, 5, sizeof(*a), COMPARE(a));
or even:
#define SORT(ARRAY, N) \
qsort(ARRAY, N, sizeof(*ARRAY), COMPARE(ARRAY))
SORT(a, 5);
That's not Standard C, so if you need compatibility between platforms, this is out of the question.

Error if i declare constant with #define or const in my C program

I use gcc version 4.3.2 (Debian 4.3.2-1.1).
I wrote a simple program in C to implement and test a integer stack. Stack is implemented by the STACK structure. I used a constant named STACKSIZE to define the STACK's size.
My program code looks like this:
#include<stdio.h>
#include<stdlib.h>
#define STACKSIZE 10;
typedef struct {
int size;
int items[STACKSIZE];
} STACK;
void push(STACK *ps, int x)
{
if (ps->size == STACKSIZE) {
fputs("Error: stack overflow\n", stderr);
abort();
} else
ps->items[ps->size++] = x;
}
int pop(STACK *ps)
{
if (ps->size == 0){
fputs("Error: stack underflow\n", stderr);
abort();
} else
return ps->items[--ps->size];
}
int main() {
STACK st;
st.size = 0;
int i;
for(i=0; i < STACKSIZE + 1; i++) {
push(&st, i);
}
while(st.size != 0)
printf("%d\n", pop(&st));
printf("%d\n", pop(&st));
return 0;
}
when i used
#define STACKSIZE 10;
gcc would return following errors:
ex_stack1.c:8: error: expected ‘]’ before ‘;’ token
ex_stack1.c:9: warning: no semicolon at end of struct or union
ex_stack1.c: In function ‘push’:
ex_stack1.c:13: error: expected ‘)’ before ‘;’ token
ex_stack1.c:17: error: ‘STACK’ has no member named ‘items’
ex_stack1.c: In function ‘pop’:
ex_stack1.c:26: error: ‘STACK’ has no member named ‘items’
ex_stack1.c: In function ‘main’:
ex_stack1.c:33: error: expected ‘)’ before ‘;’ token
when i used
const int STACKSIZE=10;
gcc would return following error:
ex_stack1.c:8: error: variably modified ‘items’ at file scope
when i used
enum {STACKSIZE=10};
gcc would compile my program successfully.
What happenned? How should i modify my program to use
#define STACKSIZE 10;
or
const int STACKSIZE=10;
Drop the semicolon, it's wrong
#define STACKSIZE 10;
^
If you keep it the preprocessor will translate int items[STACKSIZE]; into the obviously wrong int items[10;];.
For the const bit, there is a C FAQ.
The value of a const-qualified object is not a constant expression in
the full sense of the term, and cannot be used for array dimensions,
case labels, and the like.
For future reference, you can view the results of the preprocessor by making use of the -E option to gcc. That is,
gcc -E ex_stack1.c -o ex_stack1.i
Examination of the resulting ex_stack1.i file would have made the problem more obvious.
#define does textual replacement. Since you have:
#define STACKSIZE 10;
then
typedef struct {
int size;
int items[STACKSIZE];
} STACK;
becomes:
typedef struct {
int size;
int items[10;];
} STACK;
In C, const is used to declare variables that can't (easily) be modified. They are not compile-time constants.
enum, however, does define a compile-time constant. In general, you should prefer enum over const int over #define where possible. (See Advantage and disadvantages of #define vs. constants? ).

Resources