I have an unsigned char and I add integers to it but I want to get the sizeof next byte (i.e sizeof unsigned short int or unsigned int and so on).
The following code demonstrates what I want:
#include <stdio.h>
static void write_ushort(unsigned char *b, unsigned short int value) { b[1] = value >> 8; b[0] = value; }
static void write_ulong(unsigned char *b, unsigned long int value) { write_ushort(b + 2, value >> 16); write_ushort(b, value); }
static unsigned short int read_ushort(const unsigned char *b) { return b[1] << 8 | b[0]; }
static unsigned long int read_ulong(const unsigned char *b) { return read_ushort(b + 2) <<16 | read_ushort(b); }
int main() {
unsigned char b[2];
unsigned int v0; /* 4 */
unsigned short int v1; /* 2 */
v0 = 200; v1 = 1235;
write_ushort(&b[0], v0); write_ulong(&b[1], v1);
/* what i expect printf to output is:
* 4 2
* but it obviously outputs 1 1 */
printf("%d %d\n", read_ushort(&b[0]), read_ulong(&b[1]));
printf("%d %d\n", (int)sizeof(b[0]), (int)sizeof(b[1]));
return 0;
}
This isn't possible. The sizeof operator will return the size of a type, or the size of the declared type of a variable. You can't massage anything else out of it, and your code won't keep track of what type of variable a number was stored in before you assigned it to a new variable.
Regardless of the type of v0 or v1, when they're stored in elements of your array, they are converted to unsigned char.
If you want 4 2 as output, you'll need to pass sizeof(v0) and sizeof(v1) to printf, or keep track of this some other way.
C is statically typed, and you can't just change the data type of a variable (or array) by assigning something to it. In fact you can't change the data type of a variable at all: a variable corresponds (almost exactly) to a certain chunk of memory with its size defined at compile time. You can cast variables so that they are treated as though they were a different type for a specific operation, but the chunk of memory is the same size always.
And, since a variable is just a block of memory there is no way for the computer (or compiler) to know that you are using a char[2] array to store a short or a long. You have to keep track of this yourself.
Here is a major problem:
write_ulong(&b[1], v1);
You take the second byte (of a two-byte array) and pass it to write_ulong where it's handled as an array of four bytes. This means you are writing several bytes beyond the original array b and overwrite the stack. This is undefined behavior and will make your program behave very strange.
Related
I dont understand why the output of this code is 4 and not 16, Assuming that unsigned int takes 4 bytes and long int takes 8 bytes. Any help?
#include <stdio.h>
struct test {
unsigned int x;
long int y : 33;
unsigned int z;
};
int main()
{
struct test t;
unsigned int* ptr1 = &t.x;
unsigned int* ptr2 = &t.z;
printf("%d", ptr2 - ptr1);
return 0;
}
I assume you expected the output to be 16, because the offset between the pointers should be 16 bytes (assuming sizes are as you mentioned in your question).
But in c when you subtract pointers, you don't get the number of bytes but the number of elements. The elements are the data the pointers point to.
Since these are unsigned int pointers, and assuming sizeof(unsigned int) is 4, the difference between thr pointers is 4 elements.
However - as #Lundin commented above this theoretical claculation is not really relevant because subtrating pointers that do not point the same array is UB (undefined behavior).
BTW - Note when you add an integral value to a pointer, a similar thing happens on the other way: the result is the address of the pointer plus the integral value times the size of the element pointed by the pointer. E.g.: if you add 1 to unsigned int* ptr1, the resulting address will be higher than ptr1 by 4.
I wrote a pretty simple piece of C code:
int main(void) {
void *area = malloc(2 * sizeof(int));
unsigned int *int_one = (unsigned int *) area;
unsigned int *int_two = ((unsigned int *) area) + 3;
*int_two = 4293422034;
*int_one = 2;
printf("%u\n%u\n", *int_two, *int_one);
return 0;
}
sizeof(int) is 4 on my machine. Per my understanding, shouldn't the modification of memory at address int_one have an effect on the value stored at address int_two?
Modifying *int_one alters the first 4 bytes of mem. address area (perhaps not all 4, but enough to warrant the result I'm expecting?), and the integer at address int_two starts at the last byte of integer int_one.
So, shouldn't changing memory at int_one have an effect on memory at int_two?
Yet the printf call produces 4293422034 and 2 respectively.
I made sure to use unsigned variables to avoid confusion around 2s complement and negative values, and to use a small value for *int_one to warrant the change of its last byte (don't know if this is right?)
What am I not getting?
Operator '+', when applied to a pointer, increases the pointer n times the size of the object it points to. So increasing an int* by 3 does not add 3 bytes but 3*sizeof(int) bytes.
Pointer arithmetic is scaled by the size of the type the pointer points at. (sizeof(unsigned int) in your case). You'd need to cast to (char*) before adding 3 if you want to increase the address by 3 bytes, but converting that to an unsigned* pointer would incur undefined behavior by violating alignment requirements (6.3.2.3p7) and dereferencing the pointer would make the program even "more undefined" by violating strict aliasing rules (6.5p7).
To realy do this kind of type punning right, you'd need to use memcpy (or unions).
Example:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
void *area = malloc(2 * sizeof(int));
if(!area) return EXIT_FAILURE;
unsigned int *int_one_p = area;
void *int_two_p = (((char*) area) + 3); /*saving this to an (unsigned*) would be UB*/
memcpy(int_two_p,&(unsigned){4293422034},sizeof(unsigned));
memcpy(int_one_p,&(unsigned){2},sizeof(unsigned));
unsigned one,two;
memcpy(&one,int_one_p, sizeof(one));
memcpy(&two,int_two_p, sizeof(two));
printf("%u\n%u\n", two, one);
return 0;
}
learning C and now i study simple code snipper that show byte representation of primitive values:
typedef unsigned char *byte_pointer;
void show_bytes(byte_pointer start, int len) {
int i;
for (i = 0; i < len; i++)
printf(" %.2x", start[i]);
printf("\n");
}
void show_float(float x) {
show_bytes((byte_pointer) &x, sizeof(float));
}
void show_int(int x) {
show_bytes((byte_pointer) &x, sizeof(int));
}
void show_pointer(void *x) {
show_bytes((byte_pointer) &x, sizeof(void *));
}
If i understand correct, &x (an ampersand character) showing address of memory (equal to *x).
So. program routine is showing hexadecimal values of each data type, with int value of bytes like (sizeof(int)).
Im not really understand how its work. First, we typedef pointer of unsigned char, and then use it with other types. What is the meaning of (byte_pointer) &x and why does it work, when we define byte_pointer as value of type unsigned char? I understand that we get address of memory that contain value, but i don't know how exactly it work and WHY it work with char pointer. Could you explain that part?
Thanks.
The code simply takes the address of a random chunk of data and prints the contents byte by byte. The code takes the address of whatever you pass to it, then converts it to a pointer-to-byte (unsigned char). Any pointer type in C can be converted to another pointer type, although in some cases doing so is dangerous practice. In the case of char, it is safe though, you are guaranteed to get a pointer to the lowest addressed byte of the object.
Note that hiding a pointer behind a typedef is bad and dangerous practice. Just forget about that typedef, it adds nothing of value. A better way to write the same code would be:
void show_bytes (const uint8_t* start, int len)
or alternatively
void show_bytes (const void* s, int len)
{
const uint8_t* start = s;
...
byte_pointer is defined to be a pointer to an unsigned char; this is so show_bytes can print out each individual byte (in hexadecimal) of what the address passed to show_bytes points to.
I would have declared start to be a void*, and then cast it inside of show_bytes, making it a) clearer that show_bytes doesn't care what type of thing start points to, and b) avoids the cast in every call.
Trying to pass a char array as a parameter of a function but it is not being passed. Specifically, trying to pass the unsigned char array 'p' to function 'setlsbs' (ignore apparent purpose of function. just trying to pass it correctly at the moment).
The code:
#include <stdio.h>
#include <stdlib.h>
#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte) \
(byte & 0x80 ? 1 : 0), \
(byte & 0x40 ? 1 : 0), \
(byte & 0x20 ? 1 : 0), \
(byte & 0x10 ? 1 : 0), \
(byte & 0x08 ? 1 : 0), \
(byte & 0x04 ? 1 : 0), \
(byte & 0x02 ? 1 : 0), \
(byte & 0x01 ? 1 : 0)
#define PRINTBIN(x) printf(BYTETOBINARYPATTERN, BYTETOBINARY(x));
void setlsbs(unsigned char* p, unsigned char b0);
unsigned char getlsbs(unsigned char *p);
//MAIN
int main(int argc, char **argv){
//default seed
long seed = 1234;
//if argv[1] available, use it as the seed instead
if(argv[1]){
sscanf(argv[1], "%ld", &seed);
}
//seed RNG
srand(seed);
//make array for eight bytes
unsigned char *p[8];
//fill array with random num 0-255
int cnt;
for(cnt = 0; cnt<8; cnt++){
p[cnt] = (unsigned char*)(rand()%255);
printf("p[%d] decimal:%d and binary:", cnt, p[cnt]);
PRINTBIN((int)p[cnt]);
printf("\n");
}
//make random num for b0
unsigned char b0 = (unsigned char)(rand()%255);
printf("b0 decimal:%d and binary:", b0);
PRINTBIN((int)b0);
printf("\n");
//call setlsbs
setlsbs((unsigned char*)p, (unsigned char)b0);
}
//SET LSBS
void setlsbs(unsigned char *p, unsigned char b0){
printf("p[0]: %d\n", p[0]);
}
//GET LSBS
unsigned char getlsbs(unsigned char *p){
}
Results:
p[0] decimal:243 and binary:11110011
p[1] decimal:175 and binary:10101111
p[2] decimal:32 and binary:00100000
p[3] decimal:230 and binary:11100110
p[4] decimal:117 and binary:01110101
p[5] decimal:189 and binary:10111101
p[6] decimal:29 and binary:00011101
p[7] decimal:227 and binary:11100011
b0 decimal:233 and binary:11101001
p[0]: 0
That last line should be p[0]: 243
Thanks!
The first warning signal that should concern you is here:
setlsbs((unsigned char*)p, (unsigned char)b0);
Why are you casting? If p is the correct type you won't need to cast. You should write:
setlsbs(p, b0);
Of course, that won't compile because p is the wrong type. But now you are letting the compiler tell you that. Let's look at p:
unsigned char *p[8];
That is an array whose elements are of type unsigned char*. Not what you want at all. You need to declare an array whose elements are of type unsigned char:
unsigned char p[8];
You can then pass p directly to setlsbs and allow it to decay to a pointer.
You will also be able to remove the next dubious cast:
p[cnt] = (unsigned char*)(rand()%255);
You needed that cast to suppress the compilers errors when you had declared p incorrectly. With the declaration above this cast can be removed:
p[cnt] = rand()%255;
Although I suspect that you might actually mean:
p[cnt] = rand()%256;
As you have written it, rand()%255 yields a value in the range [0..254] and can never yield 255.
And then you can change:
PRINTBIN((int)p[cnt]);
to
PRINTBIN(p[cnt]);
and so on.
As a general rule, casts should be avoided. Your question illustrates a classic mistake. The compiler tells you that you made a mistake. You misinterpret the error message as indicating that you need a cast and so add a cast. The cast doesn't fix the mistake, it merely suppresses the compiler error. Now you've got an error that the compiler cannot help you with, and life suddenly gets a whole lot more complicated.
You should aim to make this code free from casts.
In your code unsigned char *p[8]; meaning p is a pointer to array of 8 unsigned char *. when p is passed to function setlsbs() function, unsigned char * at the location 0 of the array is passed! and value for that is not assigned yet. Which will be junk at that moment! In your case it is 0!
If you just want to make array of 8 bytes, try unsigned char p[8]; and then pass pointer p to the function setlsbs() function. then try to print the p[0]. you will get the proper result.
You can check the difference of unsigned char *p[8] and unsigned char (*p)[8] in this link:
Difference between *ptr[10] and (*ptr)[10]
I hope this will help you solve the problem.
I have a problem where I have a pointer to an area in memory. I would like to use this pointer to create an integer array.
Essentially this is what I have, a pointer to a memory address of size 100*300*2 = 60000 bytes
unsigned char *ptr = 0x00000000; // fictional point in memory goes up to 0x0000EA60
What i would like to achieve is to examine this memory as an integer array of size 100*150 = 15000 ints = 60000 bytes, like this:
unsigned int array[ 100 ][ 150 ];
I'm assuming it involves some casting though i'm not sure exactly how to formulate it. Any help would be appreciated.
You can cast the pointer to unsigned int (*)[150]. It can then be used as if it is a 2D array ("as if", since behavior of sizeof is different).
unsigned int (*array)[150] = (unsigned int (*)[150]) ptr;
Starting with your ptr declaration
unsigned char *ptr = 0x00000000; // fictional point in memory goes up to 0x0000EA60
You can cast ptr to a pointer to whatever type you're treating the block as, in this case array of array of unsigned int. We'll declare a new pointer:
unsigned int (*array_2d)[100][150] = (unsigned int (*)[100][150])ptr;
Then, access elements by dereferencing and then indexing just as you would for a normal 2d array.
(*array_2d)[50][73] = 27;
Some typedefs would help clean things up, too.
typedef unsigned int my_2d_array_t[100][150];
typedef my_2d_array_t *my_2d_array_ptr_t;
my_2d_array_ptr_t array_2d = (my_2d_array_ptr_t)ptr;
(*array_2d)[26][3] = 357;
...
And sizeof should work properly.
sizeof(array_2d); //4, given 32-bit pointer
sizeof(*array_2d); //60000, given 32-bit ints
sizeof((*array_2d)[0]); //600, size of array of 150 ints
sizeof((*array_2d)[0][1]); //4, size of 1 int