I'm not sure how to create a Struct in C with its variables having different bit sizes, for example:
I want to create a struct with one variable as an 8-bit integer, one variable as an 16-bit boolean, one as an 8-bit boolean, one as a 32-bit floating point number etc.
I'm coming from java so all this is very confusing, thanks.
#include <stdio.h>
#include<stdbool.h>
struct{
float d; // By default 32 bits are initialized
unsigned int a: 8;
bool my_bool_8;
bool my_bool_16;
}nibble;
int main()
{
printf("Size of structure is %lu\n", sizeof(nibble));
printf("Size of my_bool_8 is %zu\n", sizeof(nibble.my_bool_8));
return 0;
}
It depends from compiler and platform. For 8-bit integer, perhaps, you can use "int8_t" type. For 32-bit floating point - "float", but you must read documentation for your compiler.
Maybe this small example response your question:
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
struct {
uint8_t my_int_8;
int16_t my_bool_16;
bool my_bool_8;
float my_float;
} test;
int main(const int argc, const char* argv[]) {
printf("sizeof(my_int_8)=%zu\n", sizeof(test.my_int_8));
printf("sizeof(my_bool_16)=%zu\n", sizeof(test.my_bool_16));
printf("sizeof(my_bool_8)=%zu\n", sizeof(test.my_bool_8));
printf("sizeof(my_float)=%zu\n", sizeof(test.my_float));
}
Related
I wrote a small piece of code to understand how the offsetof macro works in the background. Here is the code:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = (unsigned)(&((MyStructType * )NULL)->c);
printf("offset = %u\n", offset);
return 0;
}
However, if I run it I get a warning message:
WARNING: cast from pointer to integer of different size [-Wpointer-to-int-cast]
However, if I look at the original offsetof macro in c, the code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
int main(void)
{
/* Getting the offset of a variable inside a struct */
typedef struct {
int a;
char b[23];
float c;
} MyStructType;
unsigned offset = offsetof(MyStructType, c);
printf("offset = %u\n", offset);
return 0;
}
So why do I get the warning as I cast to unsigned ? It appears to be the type for the offsetof macro. This is puzzling me.
As mch commented, unsigned is not the right type; it's 32-bit on pretty much all real-world systems. The offsetof macro is supposed to produce a result of type size_t, which is what you "should" be casting to here. I think you're confused by the code you found storing the result into an object of type unsigned; that's okay as long as they're sure the value is small, but it doesn't mean the type of the expression offsetof(MyStructType, c); was unsigned. C allows you to silently assign a larger integer type into a smaller one.
However, no matter what you do, this is not a valid implementation of offsetof and has undefined behavior (via applying -> to an invalid pointer). The way you get a working offsetof without UB is #include <stddef.h>.
Say I have an array of unsigned char of 6 bytes.
And some function modifies value in it. How would I retrieve modified values say from 0-19bit?
void my_func()
{
unsigned char tempVal[6] = { 0,0,0,0,0,0}
unsigned char* temPtr = &temVal; // Say I am using pt
int newVal;
// call external function to modify value
// fun below assign new values to tempVal[0].. till tempVal[5].
void someFuncTomodifyVal( tempPtr );
// Now I want values from say 1st19bits
// how would I achieve that? I know I have to use And condtion with 7FFFF
// so say somthing like
newValue = *tempPtr & 0x7FFFF // but then *tempPtr will give me first byte only?
}
So my question is what should I give instead of *tempPtr to get 1st 19 bits
example of
void someFuncTomodifyVal( unsigned char m[] )
{
m[0] = 'some value retrieve from other funct'
m[1] = ' values based on some cal'
m[2] = ' values based on some cal'
}
The main issue here is that you can't take a pointer to unsigned char and wildly cast it to a larger pointer type. This would result in a strict aliasing violation - undefined behavior. This can give incorrectly generated code and similar evil bugs.
To dodge this and access the array through a pointer, you could use a container type that contains the same type among its members:
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <inttypes.h>
typedef union
{
unsigned char u8 [6];
uint32_t u32;
} my_union_t;
int main()
{
unsigned char tempVal[6] = { 0x11,0x22,0x33,0x44,0x55,0x66};
my_union_t* mu = (my_union_t*)tempVal;
printf("%"PRIx32"\n", mu->u32 & 0x7FFFF);
}
As for what this will print, it depends on CPU endianess - the code is not portable. On my 32 bit little endian CPU I get 32211.
You probably intended to achieve something like this:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
unsigned char tempVal[6] = { 0x1,0x2,0x3,0x4,0,0 };
uint32_t *temPtr = (uint32_t *)tempVal; // Say I am using pt
uint32_t newVal = *temPtr;
printf("%08x\n", newVal);
newVal &= 0x7ffff;
printf("%08x\n", newVal);
}
On a little endian system the output will be:
04030201
00030201
On a big endian system the output will be:
01020304
01020304
Be aware that this is not portable as it depends on the endianness of the target system and it also violates the strict aliasing rule
Portable and correct solution:
#include <stdio.h>
#include <stdint.h>
int main(void)
{
unsigned char tempVal[6] = { 0x1,0x2,0x3,0x4,0,0 };
uint32_t value = 0;
for (int i = 0; i < 4; i++)
{
value <<= 8;
value |= tempVal[i];
}
printf("%08x\n", value);
value &= 0x7ffff;
printf("%08x\n", value);
}
Wrong answer
You can use a type which can store the 19 bits. Example : uint32_t *n = (uint32_t *) tempVal;. Now you can get the desired bits (*n) & 0x7FFFF
Good answer
You can use union to respect strict aliasing :
union foo {
unsigned char tmp[6];
unsigned int n;
};
What will be output if you will compile and execute the following c code?
void main(){
int huge*p=(int huge*)0XC0563331;
int huge*q=(int huge*)0xC2551341;
*p=200;
printf("%d",*q);
}
Assuming you meant to write the following:
#include <stdio.h>
int main(void){
int *p=(int *)0XC0563331;
int *q=(int *)0xC2551341;
*p=200;
printf("%d",*q);
return 0;
}
then the output should be whatever integer value is stored starting at address 0xC2551341.
I'm not sure what int huge is supposed to represent; wider integer types are long int and long long int (or just long and long long). Note that these wider types use the %ld and %lld conversion specifiers for output, respectively.
For my educational purposes I was wondering if there is an alternative way with memcpy() to the following code for the function address casting to an array of chars?
#include <stdio.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)
union rcast {
_vfp fp;
char fp_c[FPSZ];
} rc;
void a(void){
printf("a()\n");
}
int main(int argc, char **argv)
{
int i=0;
memset(&rc,0,FPSZ);
rc.fp=a;
for (i=0;i<FPSZ;++i)
printf("%hhx ",rc.fp_c[FPSZ-i-1]);
puts("");
printf("%p\n",a);
return 0;
}
Thanks.
Minimally modifying your code:
#include <stdio.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)
void a(void){
printf("a()\n");
}
int main(int argc, char **argv)
{
int i=0;
_vfp fp = a;
char fp_c[FPSZ];
memcpy(fp_c, &fp, FPSZ);
for (i=0;i<FPSZ;++i)
printf("%hhx ",fp_c[FPSZ-i-1]);
puts("");
printf("%p\n",a);
return 0;
}
EDIT: In response to comment, here's a version without a proxy and without memcpy
#include <stdio.h>
#include <stdint.h>
#include <limits.h>
#include <string.h>
typedef void (*_vfp)(void);
#define FPSZ sizeof(_vfp)
void a(void){
printf("a()\n");
}
int main(int argc, char **argv)
{
int i=0;
char fp_c[FPSZ];
for (i=0;i<FPSZ;++i)
fp_c[i] = (char) (((uintptr_t) &a) >> CHAR_BIT * i);
for (i=0;i<FPSZ;++i)
printf("%hhx ",fp_c[FPSZ-i-1]);
puts("");
printf("%p\n",a);
return 0;
}
For my educational purposes I was wondering if there is an alternative way with memcpy() to the following code for the function address casting to an array of chars?
Note well: though arrays and pointers are closely associated, they are very different things. Among many other differences, you can use pointer types in cast operators, and pointers as cast operands, but you cannot use array types or arrays in those contexts.
You seem to say that what you want is a char array containing the bytes of the function pointer's value (as opposed to the bytes of whatever the pointer points to). You can get that, or something like it, several ways. The simplest way is to create a char * to the pointer's value. Again, that's not an array, but it can be used in many of the same ways that an array could be used:
typedef void (*_vfp)(void);
int main(int argc, char **argv)
{
int i;
_vfp fp = a;
char *cp = &fp;
for (i = 0; i < sizeof(fp); ++i) {
printf("%hhx ", cp[i]);
}
printf("\n%p\n", (void *) a);
return 0;
}
Do note, however, that the above code exhibits undefined behavior. The %p field descriptor tells printf() that the corresponding argument is an object pointer. C draws a distinction between object pointers and function pointers, and does not define any behavior for converting between values of those two type families. I include a cast explicitly expressing such a conversion (which may enable the compiler to notice and complain); your code results in such a conversion being performed implicitly.
If you want a separate array object containing the bytes of the pointer's value (as opposed to the pointed-to function's), then you can get it in a similar way:
int main(int argc, char **argv)
{
_vfp fp = a;
char array[sizeof(fp)];
memcpy(array, &fp, sizeof(array));
/* ... */
}
That one uses memcpy(), exactly as you asked.
In any event, there is no need for a union. In fact, although your union-based approach might happen to work with your C implementation, reading from a different union member than was most recently written to formally exhibits undefined behavior.
What you are doing is formally Undefined Behaviour. C language says that an union can contain any of different variables, but you shall only access the variable that was set in the union : The size of a union is sufficient to contain the largest of its members. The value of at
most one of the members can be stored in a union object at any time. (ref : C Language Specification Draft - 6.7.2.1 Structure and union specifiers - 16)
So it is neither best nor worse than doing pointer casting via void :
intptr_t ip = (intptr_t) &a;
char *fp_c = (void *) &intptr_t;
or with memcpy :
char fp_c[FPSZ];
intptr_t ip = (intptr_t) &a;
memcpy(fp_c, &ip, sizeof(intptr_t));
All will give you same result in :
for (i=0; i<FPSZ; i++) {
printf("%hhx ",fp_c[FPSZ-i-1]);
}
fputs("\n");
I wrote this function to reverse a number. I will have test cases that are up to 2^32. I need the function to return unsigned ints. My question is this: why wont this print?
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
unsigned int reverse(unsigned int a);
int main(){
printf("%u\n",reverse(987654321));
//printf("%ui\n",reverse(987654321)); //this wont work either
return 0;
}
unsigned int reverse(unsigned int a)
{
int temp=0;
while(a>0)
{
temp=10*temp+a%10;
a/=10;
}
return temp;
}
Yes I did forget about the proto-type... Bear with me I have been doing Java and Lisp lately. However, my compiler keeps giving me a warning saying I have extra characters in the format string. It also does this if I have type "long long int" and I use "%lli% in the format string, which I also tried.
You forgot to include prototype for your function before main.
unsigned int reverse(unsigned int a);
The number probably is just too big for an unsigned on your architecture.
Remember to always enable maximum warning level for your compiler. This should have told you that reverse is not known where you use it, that you are passing an int to the %u format and also that your number ist too big.