For the problem, consider below two structures.
struct type1_A
{
int a;
char b;
char rsvd[10];
char c;
int d;
}
struct type1_B
{
int d;
char rsvd[12];
char c;
char b;
int a;
}
I need to read fields a, b, c & d from the structs. I will have a buffer address and that buffer will have one of the struct. A flag can tell what kind of struct it is.
if (flag == TYPE1_A) {
a = ((struct type1_A*) (buffer))->a;
}
else if (flag == TYPE1_B) {
a = ((struct type1_B*) (buffer))->a;
}
But when there are many such reads, I dont want to keep on having if-else like above. Is there some way (hack) that this can be done without if-else. The field names will be same but at a different offset.
You can do the pointer arithmetic manually and store the offsets in a table indexed by type. That'd replace the if-else ladder with a table lookup:
if(flag_is_within_type_range(flag))
a=*(int*) ((char*)buffer+offset_table_indexed_by_type[flag]);
Essentially the resulting assembly needs to do a dynamic_type_number-to-an_offset lookup and you having the same overloaded name (i.e., the a member) for those different offsets doesn't help anything. There's hardly any good way to exploit it.
I would use macro like this:
#define TYPE_1 1
#define GETMEMBER(type, buff, field) ((type) == TYPE_1 ? ((struct type1_A *)(buff)) -> field : ((struct type1_B *)(buff)) -> field)
void foo(void *buff)
{
int type1a = GETMEMBER(TYPE_1, buff, a);
int type2a = GETMEMBER(0, buff, a);
printf("Type1: %d, type2:%d\n", type1a, type2a);
}
If you use a constant expression as type the compiler will optimize out the comparison leaving only the assignment:
https://godbolt.org/z/a73YsorMe
Related
On an old C compiler that only passes structures by pointers I fortunately have a structure that is 4 bytes long. Which is the size of a long (not int) on this system.
The code I'm porting (awk V7 or 32V) has many functions that return this structure by value.
I'm trying to find a way to cast the structure a long and visa versa and while I have managed this for variables the cast fails with the return value of a function. I would be forced to use a temp long and then cast that. This means more than a simple define to solve my issue and means avoidable recoding.
Is there a way I can do this with just defines?
I have some sample code here that I'm playing around with. Sample code from different system has long of 64 bits so using int32 as long.
#include <stdio.h>
typedef struct _obj { char a; char b; short c; } Obj;
#define OBJ2INT *(int32*)&
#define INT2OBJ *(Obj*)&
/* Obj */ int32 newObj(a, b, c) /* was returing Obj */
char a; char b; int c;
{
Obj newobj;
newobj.a = a;
newobj.b = b;
newobj.c = c;
return OBJ2INT newobj;
}
int main(argc, argv)
int argc; char *argv[];
{
Obj a, b;
int32 t;
t = newObj('a', '1', 1));
a = INT2OBJ t; /* this works but require recoding with a temp variable */
b = INT2OBJ newObj('b', '2', 2); /* this is not allowed. even though the value is on the stack there is no address for return value */
printf("a = %c %c %d\n", a.a, a.b, a.c);
printf("b = %c %c %d\n", b.a, b.b, b.c);
}
I was missing the whole point. K & R C cannot assign or pass structures/unions.
So converting the int32 to a structure and assigning to another structure is never going to work. Can't assign structures! So the structure must always be converted to an int32. because int32 can be assigned and passed. The solution was to change this :
b = INT2OBJ newObj('b', '2', 2); /* this is not allowed. even though the value is on the stack there is no address for return value */
to this :
OBJ2INT b = newObj('b', '2', 2);
INT2OBJ is never required. What was required was moving the INT2OBJ from the right to a OBJ2INT on the left of the assignment!
I have some code which performs differently depending on the underlying data type. EG:
void *some_data = obtain_data();
int data_type = obtain_data_type();
switch(data_type)
{
case CHAR:
handle_char(some_data);
break;
case SHORT:
handle_short(some_data);
break;
case INT:
handle_int(some_data);
break;
// etc...
}
In order for this to work I need an enum or constant which assigns a numeric value to CHAR, SHORT, INT, etc. EG:
enum POD_TYPES
{
CHAR = 1,
SHORT = 2,
INT = 3
// etc.
}
"Rolling my own" is trivial here, but it seems like there ought to be a more established way of accomplishing this. Is there a standard (or at least commonly available) header file which I can include that already has these values defined somewhere? I'm not seeing anything listed in the library headers at cppreference. inttypes.h seems to come close, but upon further examination those types are all macros used for casting or determining system-specific min/max values for integers.
There are no such standard constants, no. There's a lot of things in C that you'd think would be standardized, but aren't.
As a side note, you could take the first steps towards a bit more modern C programming by using the C11 _Generic keyword and implementing polymorphism behavior instead of using run-time checking of such enums. In fact, you can get rid of the enum entirely:
// variant.h / variant.c
#include <stdio.h>
typedef void print_func_t (const void* data);
typedef struct
{
void* data;
print_func_t* print;
} variant_t;
void print_char (const void* data) { printf("%c", *(const char*) data); }
void print_short (const void* data) { printf("%hd", *(const short*) data); }
void print_int (const void* data) { printf("%d", *(const int*) data); }
void print (const variant_t* var)
{
var->print(var->data);
}
#define variant_init(var) { \
.data = &var, \
.print = _Generic((var), char: print_char, short: print_short, int: print_int) \
}
Caller:
int main()
{
char c = 'A';
short s = 3;
int i = 5;
variant_t var[3] =
{
variant_init(c),
variant_init(s),
variant_init(i)
};
for(size_t i=0; i<3; i++)
{
print(&var[i]);
printf(" ");
}
return 0;
}
This is called in C++ a variant type. There are many libraries that do this for you, such as:
QVariant from Qt
Boost any
But remember that there's a price to pay when using such a library. Things are not most efficient when you use variants, but some times it's necessary, such as when you use OPC/UA protocols.
I came across this simple program somewhere
#include<stdio.h>
#include<stdlib.h>
char buffer[2];
struct globals {
int value;
char type;
long tup;
};
#define G (*(struct globals*)&buffer)
int main ()
{
G.value = 233;
G.type = '*';
G.tup = 1234123;
printf("\nValue = %d\n",G.value);
printf("\ntype = %c\n",G.type);
printf("\ntup = %ld\n",G.tup);
return 0;
}
It's compiling (using gcc) and executing well and I get the following output:
Value = 233
type = *
tup = 1234123
I am not sure how the #define G statement is working.
How G is defined as an object of type struct globals ?
First, this code has undefined behavior, because it re-interprets a two-byte array as a much larger struct. Therefore, it is writing past the end of the allocated space. You could make your program valid by using the size of the struct to declare the buffer array, like this:
struct globals {
int value;
char type;
long tup;
};
char buffer[sizeof(struct globals)];
The #define is working in its usual way - by providing textual substitutions of the token G, as if you ran a search-and-replace in your favorite text editor. Preprocessor, the first stage of the C compiler, finds every entry G, and replaces it with (*(struct globals*)&buffer).
Once the preprocessor is done, the compiler sees this code:
int main ()
{
(*(struct globals*)&buffer).value = 233;
(*(struct globals*)&buffer).type = '*';
(*(struct globals*)&buffer).tup = 1234123;
printf("\nValue = %d\n",(*(struct globals*)&buffer).value);
printf("\ntype = %c\n",(*(struct globals*)&buffer).type);
printf("\ntup = %ld\n",(*(struct globals*)&buffer).tup);
return 0;
}
The macro simply casts the address of the 2-character buffer buf into a pointer to the appropriate structure type, then de-references that to produce a struct-typed lvalue. That's why the dot (.) struct-access operator works on G.
No idea why anyone would do this. I would think it much cleaner to convert to/from the character array when that is needed (which is "never" in the example code, but presumably it's used somewhere in the larger original code base), or use a union to get rid of the macro.
union {
struct {
int value;
/* ... */
} s;
char c[2];
} G;
G.s.value = 233; /* and so on */
is both cleaner and clearer. Note that the char array is too small.
I know that memcmp() cannot be used to compare structs that have not been memset() to 0 because of uninitialized padding. However, in my program I have a struct with a few different types at the start, then several dozen of the same type until the end of the struct. My thought was to manually compare the first few types, then use a memcmp() on the remaining contiguous memory block of same typed members.
My question is, what does the C standard guarantee about structure padding? Can I reliably achieve this on any or all compilers? Does the C standard allow struct padding to be inserted between same type members?
I have implemented my proposed solution, and it seems to work exactly as intended with gcc:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct foo
{
char a;
void *b;
int c;
int d;
int e;
int f;
};
static void create_struct(struct foo *p)
{
p->a = 'a';
p->b = NULL;
p->c = 1;
p->d = 2;
p->e = 3;
p->f = 4;
}
static int compare(struct foo *p1, struct foo *p2)
{
if (p1->a != p2->a)
return 1;
if (p1->b != p2->b)
return 1;
return
/* Note the typecasts to char * so we don't get a size in ints. */
memcmp(
/* A pointer to the start of the same type members. */
&(p1->c),
&(p2->c),
/* A pointer to the start of the last element to be compared. */
(char *)&(p2->f)
/* Plus its size to compare until the end of the last element. */
+sizeof(p2->f)
/* Minus the first element, so only c..f are compared. */
-(char *)&(p2->c)
) != 0;
}
int main(int argc, char **argv)
{
struct foo *p1, *p2;
int ret;
/* The loop is to ensure there isn't a fluke with uninitialized padding
* being the same.
*/
do
{
p1 = malloc(sizeof(struct foo));
p2 = malloc(sizeof(struct foo));
create_struct(p1);
create_struct(p2);
ret = compare(p1, p2);
free(p1);
free(p2);
if (ret)
puts("no match");
else
puts("match");
}
while (!ret);
return 0;
}
There is no guarantee of this in the C standard. From a practical standpoint it's true as part of the ABI for every current C implementation, and there seems to be no purpose in adding padding (e.g. it could not be used for checking against buffer overflows, since a conforming program is permitted to write to the padding). But strictly speaking it's not "portable".
Sadly, there is no C standard (that I have ever heard of) that allows you to control structure padding. There is the fact that automatic allocation that is initialized like this
struct something val = { 0 };
will cause all the members in val to be initialized to 0. But the padding in between is left to the implementation.
There are compiler extensions you can use like GCC's __attribute__((packed)) to eliminate most if not all structure padding, but aside from that you may be at a loss.
I also know that without major optimizations in place, most compilers won't bother to add structure padding in most cases, which would explain why this works under GCC.
That said, if your structure members cause odd alignment issues like this
struct something { char onebyte; int fourbyte; };
they will cause the compiler to add padding after the onebyte member to satisfy the alignment requirements of the fourbyte member.
Is it possible to recast the a variable permanently, or have a wrapper function such that the variable would behave like another type?
I would want to achieve something I posted in the other question:
Typecasting variable with another typedef
Update: Added GCC as compiler. May have a extension that would help?
Yes, you can cast a variable from one type to another:
int x = 5;
double y = (double) x; // <== this is what a cast looks like
However, you cannot modify the type of the identifier 'x' in-place, if that is what you are asking. Close to that, though, you can introduce another scope with that identifier redeclared with some new type:
int x = 5;
double y = (double) x;
{
double x = y; // NOTE: this isn't the same as the 'x' identifier above
// ...
}
// NOTE: the symbol 'x' reverts to its previous meaning here.
Another thing you could do, though it is really a horrible, horrible idea is:
int x = 5;
double new_version_of_x = (double) x; // Let's make 'x' mean this
#define x new_version_of_x
// The line above is pure evil, don't actually do it, but yes,
// all lines after this one will think 'x' has type double instead
// of int, because the text 'x' has been rewritten to refer to
// 'new_version_of_x'. This will likely lead to all sorts of havoc
You accomplish that by casting then assigning.
int f(void * p) {
int * i;
i = (int *)p;
//lots of code here with the i pointer, and every line
//really thinks that it is an int pointer and will treat it as such
}
EDIT From the other question you linked:
typedef struct {
unsigned char a;
unsigned char b;
unsigned char c;
} type_a;
typedef struct {
unsigned char e;
unsigned char f[2];
} type_b;
//initialize type a
type_a sample;
sample.a = 1;
sample.b = 2;
sample.c = 3;
Now sample is initialized, but you want to access it differently, you want to pretend that in fact that variable has another type, so you declare a pointer to the type you want to "disguise" sample as:
type_b * not_really_b;
not_really_b = (type_b*)&sample;
See, that is the whole magic.
not_really_b->e is equal 1
not_really_b->f[0] is equal 2
not_really_b->f[1] is equal 3
Does this answer your question?
The other answers are better (declare a variable of the type you want, and do an assignment). If that's not what you're asking for, you could use a macro:
long i;
#define i_as_int ((int)i)
printf( "i = %ld\n", i);
printf( "i = %d\n", i_as_int);
But wouldn't it be clearer to just say (int) i if that's what you mean?
As long as you realize in C pointers are nothing but addresses of memory
locations of certain types, you should have your answer. For example the
following program will print the name of the file
int main(int argc, char *argv[]) {
int *i;
i = (int *) argv[0];
printf("%s\n", argv[0]);
printf("%s\n", ((char *) i));
}