I'm trying to write a macro in C (alas, not C++) in a way to trap certain errors, in particular if I pass a name of the wrong type.
For example, with
typedef int APLNELM;
typedef int APLRANK;
#define IsScalar(a) ((a) == 0)
APLNELM AplNelm = 0;
APLRANK AplRank = 0;
Calling IsScalar (AplRank) is correct because Scalar is a Rank concept, but IsScalar (AplNelm) is wrong because Scalar is not a # elements concept.
Can some clever person find a way to write the IsScalar macro such that it checks the type of the name passed to it to ensure that it is of type APLRANK? Feel free to rewrite the original example in any equivalent way if that provides a solution.
If these are the only two types that will ever be passed into the isScalar macro, then you could do something like this:
#include <stdio.h>
struct APLNELM {
int nelm;
char a[1];
};
struct APLRANK {
int rank;
char a[2];
};
#define isScalar(b) (sizeof b.a == 2)
int main(void) {
// your code goes here
struct APLNELM temp1;
struct APLRANK temp2;
printf("%d\n", isScalar(temp1));
printf("%d\n", isScalar(temp2));
return 0;
}
The output of this code is
0
1
This will work, but I highly suggest you don't use it as it wouldn't be super maintainable:
typedef int APLNELM;
typedef int APLRANK;
typedef unsigned int TYPETRAITS;
#define TRAIT_SCALAR 0x1
#define TYPETRAITS_APLNELM TRAIT_SCALAR /*whatever else you want, up to 32 traits*/
#define TYPETRAITS_APLRANK 0/*whatever else you want, up to 32 traits*/
#define GET_TYPE_TRAITS(X) TYPETRAITS_##X
#define IS_SCALAR(X) (X & TRAIT_SCALAR)
#define IS_TYPE_SCALAR(X) IS_SCALAR(GET_TYPE_TRAITS(X))
int main()
{
const int aplnelm_traints = GET_TYPE_TRAITS(APLNELM);
const int aplrang_traints = GET_TYPE_TRAITS(APLRANK);
const bool is_aplnelm_scalar = IS_TYPE_SCALAR(APLNELM);
const bool is_aplrang_scalar = IS_TYPE_SCALAR(APLNELM);
}
I gived up with following code (requires GNU extensions: typeof and Statement Exprs):
#include <stdio.h>
typedef int APLNELM;
typedef int APLRANK;
#define IsScalar(a) \
({ \
/* Override typedefs in block scope */ \
typedef char APLNELM; \
typedef int APLRANK; \
/* Create variable with typeof(a) type; \
* then compare it by sizeof with APLNELM */ \
typeof(a) b; sizeof b == sizeof(APLNELM); \
})
int main(void)
{
APLNELM a = 5;
APLRANK b = 5;
printf("IsScalar: %d\n", IsScalar(a) ? 1 : 0);
printf("IsScalar: %d\n", IsScalar(b) ? 1 : 0);
return 0;
}
The thing is that typeof(a) is actually not replaced by APLNELM or APLRANK. C is not dynamic language, I agree that struct concept would be better suited for such differentiation.
If you want to define two integer types that are different, the straight typedef approach fails, because typedef creates synonyms for the same type, never creates new types.
There is a manner to create different integer types, but even in this case, there is no way to "detect" them through their values.
For example, observe this code:
enum myint1_e {min1 = -32767, max1 = 32767};
enum myint2_e {min2 = -32767, max2 = 32767};
typedef enum myint1_e integer1_t;
typedef enum myint2_e integer2_t;
integer1_t x1 = 0;
integer2_t x2 = 0;
Now, the two types enum myint1_t and enum myint2_t are different integer types.
See C11: 6.7.2.3.(par.5):
Two declarations of [...] enumerated types which are in different scopes or use different tags declare distinct types.
So, their typedef-ed versions are, too, different.
Thus, the variables x1 and x2 have different types.
The integer value 0 can be assigned to both variables.
Now, if you want to check that the type of a variable is the one that you want, you can try doing that:
#define VERIFY_INT1TYPE(a) ((integer1_t*)(0) == (&a))
But this method only offers a Warning message, and not the "comparisson with value false" that you expected.
Explanation: Although the integer types are, in some way, interchangeable in assignment operations, on the other hand their "pointer to" versions are always different types. Thus, a sentence like x1 == x2 has not any problem at all, but the comparisson of a value of two different pointer types will raise a warning message.
Remark: The expression (integer1_t*)(0) is the NULL pointer cast to type integer1_t*.
Example:
VERIFY_INT1TYPE(x2);
This example raise a warning message when I compiled with GCC.
One possibility is to wrap the integer in a one-field struct, to enforce strong typing. To avoid the final production code being suboptimal, compile twice with different macro definitions; once with structs to detect errors, once without structs for optimal code.
#ifdef STRONG_TYPING
#define TYPE(basetype, field) struct { basetype field; }
#define INITIALIZER(value) {(value)}
#define AS_BASETYPE(field, value) ((value).field)
#else
#define TYPE(basetype, field) basetype
#define INITIALIZER(value) (value)
#define AS_BASETYPE(field, value) (value)
#endif
typedef TYPE(int, alpnelm) APLNELM;
typedef TYPE(int, alprank) APLRANK;
#define IsScalar(a) (AS_BASETYPE(aplrank, a) == 0)
With STRONG_TYPING defined, IsScalar(SomeAplNelm) will give a compiler error. Without STRONG_TYPING, the overhead of structs will be completely gone. Naturally, all modules must to be compiled with the same definition before linking, or your executable is likely to crash.
In your program code, you will have to apply some discipline when it comes to using the macros. Declaration example:
APLNELM MyAplNelm1;
APLNELM MyAplNelm2 = INITIALIZER(0);
Assignment:
AS_BASETYPE(aplnelm, MyAplNelm1) = 0;
AS_BASETYPE(aplnelm, MyAplNelm2) = AS_BASETYPE(aplnelm, MyAplNelm1);
It is still allowed to exchange values between different 'strong' types; as long as you specify the correct type (name of the field in the struct) for each individual value.
AS_BASETYPE(aplnelm, MyAplNelm2) = AS_BASETYPE(aplrank, MyAplRank);
Please note you always need AS_BASETYPE to access a variable of one of the 'strong' types. This will make the code more verbose (please feel free to choose a shorter name for the macro), but there's nothing wrong with that. It's just a notion of metadata you are adding; it should actually improve maintainability.
Related
I am new to C and using it to program a Nordic nrf52 chip. I believe my problem is a general C one though rather than application.
I am setting up an array of structs using macros predefined in the chip SDK. Using those macros in the array initialisation works, but doing element by element does not.
So, the following works:
nrf_twi_mngr_transfer_t transfers_1[2] = { \
NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP), \
NRF_TWI_MNGR_READ (MSBARO5X_0_ADDR , &p_buffer[0], sizeof(p_buffer), 0)
};
Where:
typedef struct {
uint8_t * p_data; ///< Pointer to the buffer holding the data.
uint8_t length; ///< Number of bytes to transfer.
uint8_t operation; ///< Device address combined with transfer direction.
uint8_t flags; ///< Transfer flags (see #ref NRF_TWI_MNGR_NO_STOP).
} nrf_twi_mngr_transfer_t;
NRF_TWI_WRITE and _READ are macros that use further macros, for example:
#define NRF_TWI_MNGR_WRITE(address, p_data, length, flags) \
NRF_TWI_MNGR_TRANSFER(NRF_TWI_MNGR_WRITE_OP(address), p_data, length, flags)
which uses
#define NRF_TWI_MNGR_WRITE_OP(address) (((address) << 1) | 0)
and
#define NRF_TWI_MNGR_TRANSFER(_operation, _p_data, _length, _flags) \
{ \
.p_data = (uint8_t *)(_p_data), \
.length = _length, \
.operation = _operation, \
.flags = _flags \
}
What I want to do is change individual items in this array, for example:
transfers_1[0] = NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
However when I do that, I get the error "expected an expression".
MSBARO5X_0_ADDR is also defined in a define statement:
#define MSBARO5X_0_ADDR 0x76
If I replace this in any of the above code with a variable, I get the same "expected an expression" error. I suspect the two problems I have are due to the same lack of understanding on my part. SO forgive me for combining the two in a single post.
So the questions are:
-Why am I getting this error?
-Is it possible to change individual items in my array, and if so how?
-Is it possible to use a variable in place of the MSBARO5X_ADDR, and if so how?
Many thanks!
Ultimately, the macro expands into a brace enclosed initializer. Such a thing is not an expression, so it cannot be used as the right hand side of plain assignment (assignment and initialization are different things). It will work as part of a larger initializer, but not the way you try to use it unmodified.
But all is not lost. The syntax of the initializer implies c99 support. So we can use a trick. Structure objects can be assigned to eachother. So we need only obtain an object from somewhere. We can use a compound literal in order to create said object:
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(/*Your arguments*/);
If you define the value of a structure the moment you declare it, the compiler will infer the type of the structure from the declaration. So this here will compile:
struct coordinates {
int x;
int y;
};
struct coordinates origin = { 10, 20 }; // This is OK
But if you assign a value to a previously declared variable, the compiler cannot infer its type. This code won't compile:
struct coordinates origin;
origin = { 10, 20 }; // ERROR! The type of the rvalue is unknown!
The type is unknown, because two structures are not equivalent in C just because they have the same members. E.g. this is legal in C:
struct coordinates {
int x;
int y;
};
struct dayOfYear {
int day;
int month;
};
Now what would { 5, 8 } be? The coordinates (5/8) or the 5th of August? It could be both. All that he compiler knows is that it is a struct of type { int, int }. Yet this does not define a type in C. The following is possible in some languages but it's not possible in C:
struct dayOfYear date = { 2, 3 };
struct coordinates cords = date; // ERROR!
Despite the fact that both structures are of type { int, int }, for the compiler struct dayOfYear and struct coordinates are two completely distinct and unrelated data types.
If you want to declare a hardcoded struct value, you need to tell the compiler what kind of struct that is:
struct coordinates origin;
origin = (struct coordinates){ 10, 20 }; // This is OK
Your NRF_TWI_MNGR_TRANSFER defines a hardcoded struct but only when you use that in a definition the compiler knows the type. If you try to use it as an assignment, you need to cast to the correct type.
transfers_1[0] = (nrf_twi_mngr_transfer_t)NRF_TWI_MNGR_WRITE(MSBARO5X_0_ADDR , ®_addr[1], 1, NRF_TWI_MNGR_NO_STOP);
Which is not really a cast, even though it has the same syntax. In fact this is just telling the compiler how to interpret the following data.
Suppose we have a function like this:
void WonderfulFunction(float a)
Clearly, we can pass an int to wonderful_function and the C-compiler will promote the int to a float.
However, what about user-defined data types? Suppose we use a typedef statement to give a name/alias to a struct. Is there some way to define a promotion-rule, casting function, or constructor which will automatically convert a primitive to ADT (abstract data type)? I realize this can be done in C++, but this needs to be in C.
We want something like the following code to compile correctly:
// #include <niffty_promoter_castOperator_thing.h>
struct HappyStruct {
int happy_int;
};
typedef struct HappyStruct HappyStruct;
/* prototype */
void AnotherWonderfulFunction(HappyStruct hs)
int main( ) {
int a = 12345;
AnotherWonderfulFunction(a);
// A caster/promoter included in the
// header file specifies how to
// construct a HappyStruct from an int
return 0;
}
void AnotherWonderfulFunction(HappyStruct hs) {
// do stuff;
}
This is "possible" with generic selection (YMMV); this described here is the closest you can get in C11. (In C99, C89 this is not possible at all). Here, AnotherWonderfulFunction(X) is a macro that will expand to (AnotherWonderfulFunction)(AsHappy(X)); the parentheses ensure that the macro is not recursively expanded.
AsHappy(X) is a macro that uses generic selection to choose one from 2 utility functions - HappyAsIs takes a struct HappyStruct as a parameter and returns it as-is, whereas HappyFromInt expects an int argument, and will return it wrapped in a struct. It needs to be done using utility functions, because at least GCC does check the language constraints for other branches, even though they're not evaluated. The original X is then passed to the selected function as an argument.
#include <stdio.h>
struct HappyStruct {
int happy_int;
};
void AnotherWonderfulFunction(struct HappyStruct hs) {
printf("AnotherWonderfulFunction called with hs.happy_int = %d\n", hs.happy_int);
}
struct HappyStruct HappyAsIs(struct HappyStruct s) {
return s;
}
struct HappyStruct HappyFromInt(int val) {
return (struct HappyStruct){ val };
}
#define AsHappy(X) \
_Generic((X), \
struct HappyStruct: HappyAsIs, \
default: HappyFromInt \
)(X)
#define AnotherWonderfulFunction(X) (AnotherWonderfulFunction)(AsHappy(X))
int main(void) {
int a = 42;
float b = 65536.5;
struct HappyStruct c = { 123 };
AnotherWonderfulFunction(a);
AnotherWonderfulFunction(b);
AnotherWonderfulFunction(c);
}
and running the program produces:
% ./a.out
AnotherWonderfulFunction called with hs.happy_int = 42
AnotherWonderfulFunction called with hs.happy_int = 65536
AnotherWonderfulFunction called with hs.happy_int = 123
However, the magic disappears as soon as you take a pointer to a function;
void (*fp)(struct HappyStruct) = AnotherWonderfulFunction;
now of course fp cannot work that way because it is not a macro.
... until you make it one ...
#define fp(X) (fp)(AsHappy(X))
All this is somewhat useless, since C11 supports compound literals:
AnotherWonderfulFunction((struct HappyStruct){ 42 });
so it is of limited use - lots of black magic to save a few keystrokes.
For cases where you only care about the binary representation (i.e., not in the int-to-float case), you can use GCC's __attribute__((transparent_union))
I am writing a program which was a struct with a need to store information on what type it's holding. The data is represented inside the the struct as a pointer to void. A short example of what I mean:
#include <stdio.h>
struct foo {
void *data;
char *type;
};
int main() {
struct foo bar = {{'a', 'b', 'c'}, "char"};
printf("%s\n", (STRING_TO_TYPE(bar.type))bar.data);
return 0;
}
I need an implementation of the STRING_TO_TYPE macro that will replace "char" with char. All of this can be evaluated at compile time for the needs of my program.
What I want to do is hold an object of any type, so using an enum or checking for string equality will not work.
Short answer: it is not possible. Not your way. Macros can produce tokens (keywords, if you like), but cannot convert strings to them.
That said, if the thing you are after is really
Being able to define a struct with a "type" of its void * somewhere in the code,
Being able to access that type as a keyword from the struct's name,
then you will most likely end up with typeof. It is a GNU extension, so it will only work in GCC, but it works.
In the example code here, you define your struct of a certain "type" with the MYSTRUCT macro and get the type using the TYPE macro. The __COUNTER__ predefined macro prevents type redefining (each struct is its own type, see gcc -E) and three macro levels for MYSTRUCT are there for proper stringification of it.
#include <stdio.h>
#define TYPE(x) typeof(x.type)
#define MYSTRUCT(name, type) MYSTRUCT_INTER(name, type, __COUNTER__)
#define MYSTRUCT_INTER(name, type, counter) MYSTRUCT_RAW(name, type, counter)
#define MYSTRUCT_RAW(xName, xType, xCounter) \
struct mystruct_## xCounter { \
void * data; \
xType type; \
} xName
int main(void) {
MYSTRUCT(foo, int);
foo.data = (void *)42;
TYPE(foo) tmp = foo.data; /* <-- Here, tmp is an int */
printf("%d\n", tmp);
MYSTRUCT(bar, int*);
bar.data = &tmp;
TYPE(bar) tmp2 = bar.data; /* <-- Here, tmp2 is an int* */
printf("%p\n", tmp2);
MYSTRUCT(baz, char*);
baz.data = "Hello world";
printf("%s\n", (TYPE(baz))baz.data);
/* ^Expands to (char *) baz.data */
}
Note that I still need to know the struct's "type" to determine printf()'s format code, but solving this was not asked.
Don't forget to compile with -std=gnu** (you need it for typeof)
If I have a struct in C
typedef struct _a {
int aval;
} a;
a a_inst;
void main() {
a_inst.aval = 5;
}
how can I access "aval" without having to type as a_inst.aval for this example ??
Is this possible ?
a_inst.aval refers to "the aval part of the structure a_inst".
aval - as you want to type - would refer to "aval...?", at which point the compiler will become grumpy and refuse to cooperate.
Answer to your question: No.
(Unless, of course, you start wiggling about with #define / typedef / pointers as a means of shorthand notation, at which point you are crossing into dangerous waters of making your code less readable.)
Apart from #define or using a pointer, no.
So you could do
#define AVAL a_inst.aval
or
int * pAval= a_inst.aval
But experienced programmers will not do this.
One possible way is to use a pointer on this structure field. But you will need
void main() {
int *p_aval = &a_inst.aval;
*p_aval=...; //access
}
personnally I will prefer to type the structure name. It is explicit, doesn't harm (like few more characters to type) and is less prone to bugs.
Since the structure is composed by only one int you can set aval in this way:
*((int *) &a_inst) = 5;
printf("AVAL %d\n", a_inst.aval);
result:
AVAL 5
but i reccomend to NOT USE this kind of structure access
Just presenting this as a simple, easy to understand example.
I am assuming you want to be able to do this:
typedef struct _a {
int aval;
} a;
a a_inst;
void main() {
aval = 5; // <-- Access aval without typing a_inst.aval
}
However, that is in no reasonable way possible.
Why?
Because what if you have:
typedef struct _a {
int aval;
} a;
a a_inst;
a b_inst; // Another instance of the a struct
void main() {
aval = 5; // <-- How would the compiler know if aval refers to aval in a_inst or in b_inst?
}
I want to count the number of members in a structure.
For example:
typedef struct
{
char MrChar;
int MrInt;
long MrLong;
} Bg_Typedef;
Bg_Typedef FooStr;
I create a function prototype that should return number of members in the structure
int NumberOfMem(Bg_Typedef *psStructure);
=> NumberOfMem(&FooStr) should return 3
It can be done with X_MACRO's.
Do something like this:
#define X_BG_MEMBERS \
X(char, MrChar) \
X(int, MrInt) \
X(long, MrLong)
typedef struct {
#define X(type, member) type member;
X_BG_MEMBERS
#undef X
} Bg_Typedef;
Bg_Typedef FooStr;
Define a function which will count the members. Can also just be a variable, but make the variable static const so that it is not overwritten
static int
bg_members_count() {
#define X(_, __) +1
static int COUNT = 0
X_BG_MEMBERS;
#undef X
return COUNT;
}
Now you can do something like this in main:
#include <stdio.h>
...
int main() {
printf("The number of members defined in Bg_Typedef is %d\n", bg_members_count());
}
You should get something like:
The number of members defined in Bg_Typedef is 3
You might also just want a constant, so you can do the following
#define X(_, __) +1
static const int COUNT = X_BG_MEMBERS;
#undef X
Alternative Pattern
In order to avoid having lots of #define X... followed by #undef X, it may be beneficial to do something like this instead:
#define X_BG_MEMBERS(X) \
X(char, MrChar) \
X(int, MrInt) \
X(long, MrLong)
#define BG_STRUCT_FIELD(type, field) type field;
#define BG_COUNT_MEMBER(_, __) +1
typedef struct {
X_BG_MEMBERS(BG_STRUCT_FIELD)
} Bg_Typedefarguably;
static int
bg_members_count() {
static int COUNT = X_BG_MEMBERS(BG_COUNT_MEMBER);
return COUNT;
}
// OR constant
// static const int COUNT = X_BG_MEMBERS(BG_COUNT_MEMBER);
It works the same as the above, but should be noticeably more readable. See ref.
There is no way to do this that is inbuilt into the C language AFAIK. If you want to do this you would need to remember the number of members or hard code the number as return value of your function. C can tell you the size in bytes of your structs but not the number of members they contain. Alternatively you could use a member function of your struct to return the hard coded number of members.
C only allows you to determine the number of bytes a structure requires (including padding bytes) using the sizeof operator. As long as the struct members all have the same type, you can use sizeof(struct foo)/sizeof(membertype) to compute the number of members. In the general case, with differently sized member types, this is impossible from within the C language (you could post process the source automatically and fill in the result, but that's ugly). C simply does not allow what is called Introspection in other languages (like e.g. perl).
But then, you (and the compiler) know the number of members at compile time. Why do you want to compute a known number at runtime? Maybe you can state the actual problem you are trying to solve and we can point to a solution not involving member counts...
This cannot be done in C.
If you really need this, you should try a more high level language which supports reflection. (Java, Python ).
http://en.wikipedia.org/wiki/Reflection_%28computer_programming%29