How casting of array address are coming differently in C - c

After long time, I was doing some experiments on array with this program and printing output in decimal using %lu.
The confusing part I observed is when I use cast with unsigned long, array address '&thing+1' increment by just +1,
140733866717248 140733866717248
140733866717249 140733866717249
When I don't cast then array addresses,
140720750924480 140720750924480
140720750924481 140720750924488
How address in first part increment by just 1 on int type address '&'?
How casting affect the values here?
Example program:
#include <stdio.h>
int main(void)
#if 0 /* (unsigned long)&thing --> 140733866717248
(unsigned long)&thing+1 --> 140733866717249*/
{
int thing[8];
printf("%lu %lu\n", (unsigned long)thing, (unsigned long)&thing );
printf("%lu %lu\n", (unsigned long)thing+1, (unsigned long)&thing+1);
return 0;
}
#endif
#if 1 /* &thing --> 140720750924480
&thing+1 --> 140720750924488*/
{
int thing[8];
printf("%lu %lu\n", thing, &thing );
printf("%lu %lu\n", thing+1, &thing+1);
return 0;
}
#endif

In the first example, you are adding 1 to unsigned long values, so that just adds 1
In the second example, you are adding 1 to a pointer, which increases the pointer value by the size of the pointed at type. So with thing + 1, thing is an int *, so it increases by sizeof(int), while with &thing +1, &thing is an int (*)[8], so it increases by the size of that (32).
Result from running the code you posted:
140733007047872 140733007047872
140733007047876 140733007047904

Related

why itoa fuction returns 32 bits if the size of variable in 16 bit

size of short int is 2 bytes(16 bits) on my 64 bit processor and mingw compiler but when I convert short int variable to a binary string using itoa function
it returns string of 32 bits
#include<stdio.h>
int main(){
char buffer [50];
short int a=-2;
itoa(a,buffer,2); //converting a to binnary
printf("%s %d",buffer,sizeof(a));
}
Output
11111111111111111111111111111110 2
The answer is in understanding C's promotion of short datatypes (and char's, too!) to int's when those values are used as parameters passed to a function and understanding the consequences of sign extension.
This may be more understandable with a very simple example:
#include <stdio.h>
int main() {
printf( "%08X %08X\n", (unsigned)(-2), (unsigned short)(-2));
// Both are cast to 'unsigned' to avoid UB
return 0;
}
/* Prints:
FFFFFFFE 0000FFFE
*/
Both parameters to printf() were, as usual, promoted to 32 bit int's. The left hand value is -2 (decimal) in 32bit notation. By using the cast to specify the other parameter should not be subjected to sign extension, the printed value shows that it was treated as a 32 bit representation of the original 16 bit short.
itoa() is not available in my compiler for testing, but this should give the expected results
itoa( (unsigned short)a, buffer, 2 );
your problem is so simple , refer to itoa() manual , you will notice its prototype which is
char * itoa(int n, char * buffer, int radix);
so it takes an int that to be converted and you are passing a short int so it's converted from 2 byte width to 4 byte width , that's why it's printing a 32 bits.
to solve this problem :
you can simply shift left the array by 16 position by the following simple for loop :
for (int i = 0; i < 17; ++i) {
buffer[i] = buffer[i+16];
}
and it shall give the same result , here is edited version of your code:
#include<stdio.h>
#include <stdlib.h>
int main(){
char buffer [50];
short int a= -2;
itoa(a,buffer,2);
for (int i = 0; i < 17; ++i) {
buffer[i] = buffer[i+16];
}
printf("%s %d",buffer,sizeof(a));
}
and this is the output:
1111111111111110 2

what is behavior when char is compared with unsigned short in c language?

When I run the following program:
void func(unsigned short maxNum, unsigned short di)
{
if (di == 0) {
return;
}
char i;
for (i = di; i <= maxNum; i += di) {
printf("%u ", i);
}
printf("\n");
}
int main(int argc, char **argv)
{
func(256, 100);
return 0;
}
It is endless loop, but i wonder when char is compared with unsigned short, is char translated to unsigned short? In this situation, char is overflow and larger than maxNum. I really do not know how to explain the results of this program.
Implementation defined behavior, Undefined behavior and CHAR_MAX < 256
Let us sort out:
... unsigned short maxNum
... unsigned short di
char i;
for (i = di; i <= maxNum; i += di) {
printf("%u ", i);
}
char may be a signed char or an unsigned char. Let us assume it is signed.
unsigned short may have the same range as unsigned when both are 16-bit. Yet it is more common to find unsigned short as 16-bit and int, unsigned as 32-bit.
Other possibles exist, yet let us go forward with the above two assumptions.
i = di could be interesting if the value assigned was outside the range of a char, but 100 is always within char range, so i is 100.
Each argument in i <= maxNum goes through usual integer promotions so the signed char i first becomes an int 100 and the 16-bit maxNum becomes an int 256. As 100 < 256 is true, the loop body is entered. Notice i would never expect to have a value as large as 256 since CHAR_MAX is less than 256 - even on following loops - This explains the seen forever loop. But wait there's more
With printf("%u ", i);, printf() expects a matching unsigned argument. But i as a type with less range then int gets promoted to a int with the same value as part of a ... argument. Usually printing mis-matched specifiers and type is undefined behavior with an exception: when the value is representable as both a signed and unsigned type. As 100 is the first time, all is OK.
At the loop end, i += di is like i = i + di;. The addition arguments go through usual integer promotions and become int 100 added to int 100. That sum is 200. So far nothing strange. Yet assigning a 200 to a signed char coverts the 200 as it is out of range. This is implementation defined behavior. The assigned value could have been 0 or 1 or 2.... Typically, the value is wrapped around ("modded") by adding/subtracting 256 until in range. 100 + 100 -256 --> -56.
But the 2nd printf("%u ", i); attempts printing -56 and that is undefined behavior.
Tip: enable all warnings, Good compilers will point out many of these problems and save you time.
I got the answer from http://www.idryman.org/blog/2012/11/21/integer-promotion/ , both char and unsigned short are translated to int which can explain the process and result of this programs.

long long multiplication in C gives wrong result

My C code seems to be malfunctioning and incapable of multiplying long long numbers and outputting the result, and I can't for the life of me figure out why.
Here's the culprit code:
#include "stdio.h"
int main()
{
unsigned long long primes[] = {199453LL, 200723LL, 203317LL, 205103LL, 206603LL, 208057LL, 210323LL, 210961LL, 212827LL, 214237LL, 215693LL, 216319LL};
unsigned long long numbers[6];
int i;
printf("Calculating the numbers to factor!\n");
printf("Size of long: %i\n", sizeof(long));
printf("Size of long long: %i\n", sizeof(long long));
for (i = 0; i < 6; i++)
{
numbers[i] = primes[i]*primes[11-i];
printf("%ld*%ld = %ld\n", primes[i], primes[11-i], numbers[i]);
printf("Result is %ld\n",numbers[i]);
}
return 0;
}
And here's the output when I compile this and run it (I'm using gcc version 4.8.2 on Linux)
Calculating the numbers to factor!
Size of long: 4
Size of long long: 8
199453*0 = 216319
Result is 195800547
200723*0 = 215693
Result is 344873079
203317*0 = 214237
Result is 608351169
205103*0 = 212827
Result is 701783221
206603*0 = 210961
Result is 635502523
208057*0 = 210323
Result is 809499451
Your printf format string is wrong. %ld requires a long int, %lld is for a long long int, and since you are using unsigned long long, you should use %llu, otherwise large positive values will be displayed as negative.
And, as noticed by Grzegorz Szpetkowski, the size_t (sizeof) requires %zu.
From printf(3):
l (ell) A following integer conversion corresponds to a long int or unsigned long int argument, or a following n conversion
corresponds to a pointer to a long int argument, or a following c conversion corresponds to a wint_t argument, or a following s conversion corresponds to a pointer to wchar_t argument.
ll (ell-ell). A following integer conversion corresponds to a long long int or unsigned long long int argument, or a following
n conversion corresponds to a pointer to a
long long int argument.
...
z A following integer conversion corresponds to a size_t or ssize_t argument. (Linux libc5 has Z with this meaning. Don't use it.)
Now, for example this output
199453*0 = 216319
Occurs because the little-endian 64-bit numbers 199453, 216319 and 43145473507 are correctly pushed onto the stack; but printf expects to find only 32-bit numbers on the stack, so it prints 199453, 0 (which are the top 4 bytes of 64-bit number 199453), and 216319.

Data stored with pointers

void *memory;
unsigned int b=65535; //1111 1111 1111 1111 in binary
int i=0;
memory= &b;
for(i=0;i<100;i++){
printf("%d, %d, d\n", (char*)memory+i, *((unsigned int * )((char *) memory + i)));
}
I am trying to understand one thing.
(char*)memory+i - print out adress in range 2686636 - 2686735.
and when i store 65535 with memory= &b this should store this number at adress 2686636 and 2686637
because every adress is just one byte so 8 binary characters so when i print it out
*((unsigned int * )((char *) memory + i)) this should print 2686636, 255 and 2686637, 255
instead of it it prints 2686636, 65535 and 2686637, random number
I am trying to implement memory allocation. It is school project. This should represent memory. One adress should be one byte so header will be 2686636-2586639 (4 bytes for size of block) and 2586640 (1 byte char for free or used memory flag). Can someone explain it to me thanks.
Thanks for answers.
void *memory;
void *abc;
abc=memory;
for(i=0;i<100;i++){
*(int*)abc=0;
abc++;
}
*(int*)memory=16777215;
for(i=0;i<100;i++){
printf("%p, %c, %d\n", (char*)memory+i, *((char *)memory +i), *((char *)memory +i));
}
output is
0028FF94,  , -1
0028FF95,  , -1
0028FF96,  , -1
0028FF97, , 0
0028FF98, , 0
0028FF99, , 0
0028FF9A, , 0
0028FF9B, , 0
i think it works. 255 only one -1, 65535 2 times -1 and 16777215 3 times -1.
In your program it seems that address of b is 2686636 and when you will write (char*)memory+i or (char*)&b+i it means this pointer is pointing to char so when you add one to it will jump to only one memory address i.e2686637 and so on till 2686735(i.e.(char*)2686636+99).
now when you are dereferencing i.e.*((unsigned int * )((char *) memory + i))) you are going to get the value at that memory address but you have given value to b only (whose address is 2686636).all other memory address have garbage values which you are printing.
so first you have to store some data at the rest of the addresses(2686637 to 2686735)
good luck..
i hope this will help
I did not mention this in my comments yesterday but it is obvious that your for loop from 0 to 100 overruns the size of an unsigned integer.
I simply ignored some of the obvious issues in the code and tried to give hints on the actual question you asked (difficult to do more than that on a handy :-)). Unfortunately I did not have time to complete this yesterday. So, with one day delay my hints for you.
Try to avoid making assumptions about how big a certain type is (like 2 bytes or 4 bytes). Even if your assumption holds true now, it might change if you switch the compiler or switch to another platform. So use sizeof(type) consequently throughout the code. For a longer discussion on this you might want to take a look at: size of int, long a.s.o. on Stack Overflow. The standard mandates only the ranges a certain type should be able to hold (0-65535 for unsigned int) so a minimal size for types only. This means that the size of int might (and tipically is) bigger than 2 bytes. Beyond primitive types sizeof helps you also with computing the size of structures where due to memory alignment && packing the size of a structure might be different from what you would "expect" by simply looking at its attributes. So the sizeof operator is your friend.
Make sure you use the correct formatting in printf.
Be carefull with pointer arithmetic and casting since the result depends on the type of the pointer (and obviously on the value of the integer you add with).
I.e.
(unsigned int*)memory + 1 != (unsigned char*)memory + 1
(unsigned int*)memory + 1 == (unsigned char*)memory + 1 * sizeof(unsigned int)
Below is how I would write the code:
//check how big is int on our platform for illustrative purposes
printf("Sizeof int: %d bytes\n", sizeof(unsigned int));
//we initialize b with maximum representable value for unsigned int
//include <limits.h> for UINT_MAX
unsigned int b = UINT_MAX; //0xffffffff (if sizeof(unsigned int) is 4)
//we print out the value and its hexadecimal representation
printf("B=%u 0x%X\n", b, b);
//we take the address of b and store it in a void pointer
void* memory= &b;
int i = 0;
//we loop the unsigned chars starting at the address of b up to the sizeof(b)
//(in our case b is unsigned int) using sizeof(b) is better since if we change the type of b
//we do not have to remember to change the sizeof in the for loop. The loop works just the same
for(i=0; i<sizeof(b); ++i)
{
//here we kept %d for formating the individual bytes to represent their value as numbers
//we cast to unsigned char since char might be signed (so from -128 to 127) on a particular
//platform and we want to illustrate that the expected (all bytes 1 -> printed value 255) occurs.
printf("%p, %d\n", (unsigned char *)memory + i, *((unsigned char *) memory + i));
}
I hope you will find this helpfull. And good luck with your school assignment, I hope you learned something you can use now and in the future :-).

Unexpected output from strtol

I'm trying to create a small program that takes in a physical memory location and prints the data stored at the location. I'm passing two parameters into the program - the address, and the size (in bytes) of memory I want to print.
The issue I'm having is when the address I pass in gets above a certain value the strtol() function passes out a nonsensical value. Code below:
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <asm-generic/fcntl.h>
#include <unistd.h>
int main(int argc, char** argv)
{
unsigned int mem_address,mem_size;
int loop, i;
int *ptr, *mem_address_current;
printf("mem_addr: %s\n",argv[1]);
printf("mem_size: %s\n",argv[2]);
mem_address = strtol(argv[1], NULL, 16);
mem_size = strtol(argv[2], NULL, 16);
printf("mem_addr: %x\n",mem_address);
printf("mem_size: %x\n",mem_size);
int mem_dev = open("/dev/mem", O_RDWR);
if(mem_dev == -1)
{
printf("No worky\n");
exit(1);
}
int alloc_mem_size, page_mask, page_size;
void *mem_pointer, *virt_addr;
page_size = sysconf(_SC_PAGESIZE);
alloc_mem_size = (((mem_size / page_size) + 1) * page_size);
page_mask = (page_size - 1);
mem_pointer = mmap(NULL,
alloc_mem_size,
PROT_READ | PROT_WRITE,
MAP_SHARED,
mem_dev,
(mem_address & ~page_mask)
);
if(mem_pointer == MAP_FAILED)
{
printf("no_worky2\n");
exit(1) ;
}
virt_addr = (mem_pointer + (mem_address & page_mask));
ptr = mem_pointer;
loop = (mem_size/16) + 1;
for(i = 0;i < loop;i++) {
printf("%#x: %08x %08x %08x %08x\n", ptr, *ptr, *(ptr + 1), *(ptr + 2), *(ptr + 3));
ptr = ptr + 4;
}
return 0;
}
If I run the the following command, I get the expected values.
root#p1025:~# ./test_prog_ppc 0100000 16
mem_addr: 0100000
mem_size: 16
mem_addr: 100000
mem_size: 16
0x48001000: 38210020 4e800020 9421ffe0 7c0802a6
0x48001010: 2c050000 bf410008 7c7e1b78 90010024
However, If I change the input address the value changes from what is expected:
root#p1025:~# ./test_prog_ppc ffee0000 16
mem_addr: ffee0000
mem_size: 16
mem_addr: 7fffffff
mem_size: 16
Any ideas as to why this would happen?
Thanks for the help.
strtol() returns a (signed) long. Based on your input, you are trying to parse unsigned 32 bit numbers, so if long is 32 bits on your system, strtol() is going to go out of range. In this case, it will return LONG_MAX, which on your system appears to be 0x7FFFFFFF.
You should use strtoul() instead, and store the result in an unsigned long, rather than an unsigned int as you are now, since while long is guaranteed to be at least 32 bits, int is not.
In addition, you really ought to be passing the address of a real pointer as the second argument to strtol() and friends, and using it to check for errors. Right now, if either of argv[1] or argv[2] did not start with a number, you wouldn't be able to distinguish whether the input was bad, or whether the input was a legitimate zero.
This behaviour is documented, see strtol
RETURN VALUE
...
If the correct value is outside the range of representable values, {LONG_MIN}, {LONG_MAX}, {LLONG_MIN}, or {LLONG_MAX} shall be returned (according to the sign of the value), and errno set to [ERANGE].
Your return value is LONG_MAX and when you test errno, it should be ERANGE.
You could use one of strtoul, strtoll or strtoull, which all would be able to handle larger values. Although strtoul is restricted to unsigned long, so if you are on a 64 bit system, you should use one of the strto*ll functions.

Resources