Discrepancy in size of long int - c

I'm getting a size discepancy while using long int in C. The following code:
#include <stdio.h>
void main()
{
printf("%d\n", sizeof(long int));
}
gives 8 as output, so 64 bits are used to represent long int, right? But:
#include <stdio.h>
void main()
{
long int a;
a = 1;
a = a << 32;
printf("%d\n", a);
}
gives 0 (shifting by 31 gives -2147483648, which is -2**31). So, it seems that only 4 bytes are being used. What does this mean? I'm using gcc 4.4.5 with no flags

You're printing it as a normal integer: printf("%d"). Try printing it as a long integer: printf("%ld ...").

Related

warning: integer constant is too large for its type

how to find the correct type for largest number ?
#include <stdio.h>
/**
* factor_prime - prints the prime factors of a number
* #n: number
*/
void factor_prime(unsigned long long n)
{
long i;
long inter = n;
printf("n : %lld\n", n);
for (i = 2; i <= n; i++)
{
if (n % i == 0)
{
n = n / i;
printf("%ld=%lld*%ld\n", inter, n, i);
return;
}
}
}
int main(void)
{
factor_prime(1718944270642558716715u);
}
output : 3397071787570416427=35568825191561*95507
expected : 1718944270642558716715=343788854128511743343*5
how to fix ?
You are using a too big integer constant that can not be represented in any object of an integer type.
Consider this demonstration program.
#include <stdio.h>
#include <limits.h>
#include <inttypes.h>
int main( void )
{
printf( "%llu\n", ULLONG_MAX );
printf( "%" PRIuMAX "\n", UINTMAX_MAX );
}
Its output is
18446744073709551615
18446744073709551615
The outputted constant contains only 20 digits while your constant 1718944270642558716715u that you are trying to use contains 22 digits.
Pay attention to that in any case your function is incorrect. The function parameter has the type unsigned long long that you are assigning to a variable of the signed type long
void factor_prime(unsigned long long n)
{
long i;
long inter = n;
//...
As you are trying to pass a very big number then the assignment results in getting an invalid value.
The problem with your code is that you're passing a value i.e. 1718944270642558716715u which is out of range for the unsigned long long numeric limit.
You can check the numeric limit of a type using:
For c++
std::numeric_limits<unsigned long long>::max() // 18446744073709551615
For C
#include <stdio.h>
#include <limits.h>
int main(void)
{
printf("%llu", ULONG_LONG_MAX); // 18446744073709551615
}
when you code a function that you want to work for any type of variable try to use the largest variable size. In your case try long long or decimal.

Cant i store 4294967295 in unsigned int ? Int is 4 bytes on my machine

Why am i getting 0 ?? And compiler warning:
format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘long unsigned int’
Here is the code :
#include <stdio.h>
//function declerations...
int power(int base, int on);
int main(void) {
printf("%d",power(2, sizeof(int)*8)-1);
return 0;
}
int power(int base, int on) {
int pf = 1;
for (int i = 0; i < on; i++) {
pf *= base;
}
return pf;
}
If int is 4 bytes on my system,i guess i should be able to store 4294967295 in unsigned int.
If your int or unsigned int is 32-bits, neither can store the value 4294967296 since this is 2**32 which would require a 64-bit type.
Even uint32_t can only store the max value 2**32 - 1 so your value is just 1 out of range.
But int32_t can store the max positive value 2**31 - 1 so the signed type is even further off.
Assuming an int is 4 bytes and you have 8 bit bytes, then int is 32 bits wide. Subsequently a signed int (if negatives are represented in 2's complement) has a range of -2147483648 to 2147483647 while unsigned int has a range of 0 to 4294967295.
The value 4294967296 in binary is 1 00000000 00000000 00000000 00000000. This is 33 bits. So 4294967296 is too big for this type.
I am back after long time (obviously) to this question, and I am not sure why everyone thinks OP meant to store 4294967296 when he wanted to store 4294967295 as asked in the question, maybe OP changed the question later, and no one bothered to re-answer. Now, back to question.
You can store 4294967295 in unsigned int, but the problem is in your printing, you are doing printf("%d", 4294967295) which means print 4294967295 as a signed int, but the number 4294967295 cannot be stored in signed int, so, narrowing conversion happens.
You need to print the unsigned int that you've got with %u rather than %d.
#include <stdio.h>
int power(int base, int pow);
int main(){
printf("Size of unsigned int: %d\n", sizeof(unsigned int));
unsigned int the_number = power(2, sizeof(int)*8)-1;
printf("Wrongly printed: %d\n", the_number);
printf("Correctly printed: %u\n", the_number);
return 0;
}
int power(int base, int on) {
int pf = 1;
for (int i = 0; i < on; i++) {
pf *= base;
}
return pf;
}

Why this function in c is giving unexpected results?

I'm learning C function construction and I'm trying to make an exponent function with two arguments: base & exponent.
#include <stdio.h>
#include <stdlib.h>
int power(int a,int b){
int c;
int i;
c=1;
for(i=1;i<=b;++i){
c=c*a;
}
return c;
}
int main(){
int nice=power(5,20);
printf("answer =%d , and size is=%d ", nice, sizeof(nice));
return 0;
}
When I execute the program, it gives me the following output:
answer =1977800241 ,and size is=4
EDIT:
But when I execute power(5,2), it gives a perfect result of 25.
It is having integer overflow. You have to use unsigned long long or long long .
#include <stdio.h>
#include <stdlib.h>
typedef long long ll;
ll power(ll a,ll b){
ll c,i;
c=1;
for(i=1;i<=b;++i){
c=c*a;
}
return c;
}
int main(){
ll nice=power(5,20);
printf("answer =%lld , and size is=%lld ", nice, sizeof(nice));
return 0;
}
NOTE:
You will have a good idea about this -> read this SO question.
QUESTION-2: WHat happens for a=5 b=100
Then you have to write your custom function for manipulating the multiplications. Use int arr[100] to hold the digits of the large number and then multiply it accordingly.C/C++ doesn't provide anything like BIgInt of Java, you have to build it.

weird output without typecasting

I was trying to execute this code through gcc compiler:
#include <stdio.h>
int main()
{
unsigned long long int x;
x = 75000 * 75000;
printf ("%llu\n", x);
return 0;
}
But it gave wrong output.
I then tried this:
#include <stdio.h>
int main()
{
unsigned long long int x;
x = (unsigned long long)75000 * (unsigned long long)75000;
printf ("%llu\n", x);
return 0;
}
And it gave correct output !
Why is this so?
The expression 75000 * 75000 is the multiplication of two integer constants. The result of this expression is also an integer and can overflow. The result is then assigned to an unsigned long long, but it has already overflowed so the result is wrong.
To write unsigned long long constants use the ULL suffix.
x = 75000ULL * 75000ULL;
Now the multiplication will not overflow.

How to combine two 32-bit integers into one 64-bit integer?

I have a count register, which is made up of two 32-bit unsigned integers, one for the higher 32 bits of the value (most significant word), and other for the lower 32 bits of the value (least significant word).
What is the best way in C to combine these two 32-bit unsigned integers and then display as a large number?
In specific:
leastSignificantWord = 4294967295; //2^32-1
printf("Counter: %u%u", mostSignificantWord,leastSignificantWord);
This would print fine.
When the number is incremented to 4294967296, I have it so the leastSignificantWord wipes to 0, and mostSignificantWord (0 initially) is now 1. The whole counter should now read 4294967296, but right now it just reads 10, because I'm just concatenating 1 from mostSignificantWord and 0 from leastSignificantWord.
How should I make it display 4294967296 instead of 10?
It might be advantageous to use unsigned integers with explicit sizes in this case:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
uint32_t leastSignificantWord = 0;
uint32_t mostSignificantWord = 1;
uint64_t i = (uint64_t) mostSignificantWord << 32 | leastSignificantWord;
printf("%" PRIu64 "\n", i);
return 0;
}
Output
4294967296
Break down of (uint64_t) mostSignificantWord << 32 | leastSignificantWord
(typename) does typecasting in C. It changes value data type to typename.
(uint64_t) 0x00000001 -> 0x0000000000000001
<< does left shift. In C left shift on unsigned integers performs logical shift.
0x0000000000000001 << 32 -> 0x0000000100000000
| does 'bitwise or' (logical OR on bits of the operands).
0b0101 | 0b1001 -> 0b1101
long long val = (long long) mostSignificantWord << 32 | leastSignificantWord;
printf( "%lli", val );
my take:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
data64 = (unsigned long long) high << 32 | low;
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Another approach:
unsigned int low = <SOME-32-BIT-CONSTRANT>
unsigned int high = <SOME-32-BIT-CONSTANT>
unsigned long long data64;
unsigned char * ptr = (unsigned char *) &data;
memcpy (ptr+0, &low, 4);
memcpy (ptr+4, &high, 4);
printf ("%llx\n", data64); /* hexadecimal output */
printf ("%lld\n", data64); /* decimal output */
Both versions work, and they will have similar performance (the compiler will optimize the memcpy away).
The second version does not work with big-endian targets but otoh it takes the guess-work away if the constant 32 should be 32 or 32ull. Something I'm never sure when I see shifts with constants greater than 31.
There's another way using arrays and pointers:
#include <stdio.h>
#include <inttypes.h>
int main(void) {
// Two uint32_t to one uint64_t
uint32_t val1[2] = {1000, 90000};
uint64_t *val1_u64_ptr = (uint64_t*)val1; //intermediate pointer cast to avoid Wstrict-aliasing warnings
uint64_t val2 = *val1_u64_ptr;
printf("val2: %" PRIu64 "\n", val2);
// val2: 386547056641000
// back to uint32_t array from uint64_t
uint64_t val3 = 386547056641000ull;
uint32_t *val4 = (uint32_t*)&val3;
printf("val4: %" PRIu32 ", %" PRIu32 "\n", val4[0], val4[1]);
// val4: 1000, 90000
return 0;
}
This code for me is much easier to understand and read. You are just creating a contiguous space in memory with two 32-bit unsigned int and then this same memory space is read as a single 64-bit unsigned int value and vice-versa. There are no operations involved only memory being read as different types.
EDIT
Forgot to mention that this is great if you already have a 64-bit array read from somewhere then you could easily read everything as 32-bit array pairs:
#include <stdio.h>
#include <inttypes.h>
int main() {
uint64_t array64[] = {
386547056641000ull,
93929935171414ull,
186655006591110ull,
73141496240875ull,
161460097995400ull,
351282298325439ull,
97310615654411ull,
104561732955680ull,
383587691986172ull,
386547056641000ull
};
int n_items = sizeof(array64) / sizeof(array64[0]);
uint32_t* array32 = (uint32_t*)&array64;
for (int ii = 0; ii < n_items * 2; ii += 2) {
printf("[%" PRIu32 ", %" PRIu32 "]\n", array32[ii], array32[ii + 1]);
}
return 0;
}
Output:
[1000, 90000]
[3295375190, 21869]
[22874246, 43459]
[2498157291, 17029]
[3687404168, 37592]
[1218152895, 81789]
[3836596235, 22656]
[754134560, 24345]
[4162780412, 89310]
[1000, 90000]
Using union struct
Still better and more readable would be to use a struct union as from https://stackoverflow.com/a/2810339/2548351:
#include <stdio.h>
#include <inttypes.h>
typedef union {
int64_t big;
struct {
int32_t x;
int32_t y;
};
} xy_t;
int main() {
// initialize from 64-bit
xy_t value = {386547056641000ull};
printf("[%" PRIu32 ",%" PRIu32 "]\n", value.x, value.y);
// [1000, 90000]
// initialize as two 32-bit
xy_t value2 = {.x = 1000, .y = 90000};
printf("%" PRIu64, value.big);
// 386547056641000
return 0;
}
Instead of attempting to print decimal, I often print in hex.
Thus ...
printf ("0x%x%08x\n", upper32, lower32);
Alternatively, depending upon the architecture, platform and compiler, sometimes you can get away with something like ...
printf ("%lld\n", lower32, upper32);
or
printf ("%lld\n", upper32, lower32);
However, this alternative method is very machine dependent (endian-ness, as well as 64 vs 32 bit, ...) and in general is not recommended.
Hope this helps.
This code works when both upper32 and lower32 is negative:
data64 = ((LONGLONG)upper32<< 32) | ((LONGLONG)lower32& 0xffffffff);
You could do it by writing the 32-bit values to the right locations in memory:
unsigned long int data64;
data64=lowerword
*(&((unsigned int)data64)+1)=upperword;
This is machine-dependent however, for example it won't work correctly on big-endian processors.
Late at the game, but I needed such a thing similar to represent a numerical base10 string of a 64bit integer on a 32bit embedded env..
So, inspired by Link I wrote this code that can do what asked in the question, but not limiting on base10: can convert to any base from 2 to 10, and can be easly extended to base N.
void stringBaseAdd(char *buf, unsigned long add, int base){
char tmp[65], *p, *q;
int l=strlen(buf);
int da1, da2, dar;
int r;
tmp[64]=0;
q=&tmp[64];
p=&buf[l-1];
r=0;
while(add && p>=buf){
da1=add%base;
add/=base;
da2=*p-'0';
dar=da1+da2+r;
r=(dar>=base)? dar/base: 0;
*p='0'+(dar%base);
--p;
}
while(add){
da1=add%base;
add/=base;
dar=da1+r;
r=(dar>=base)? dar/base: 0;
--q;
*q='0'+(dar%base);
}
while(p>=buf && r){
da2=*p-'0';
dar=da2+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
--q;
*q='0'+r;
}
l=strlen(q);
if(l){
memmove(&buf[l], buf, strlen(buf)+1);
memcpy(buf, q, l);
}
}
void stringBaseDouble(char *buf, int base){
char *p;
int l=strlen(buf);
int da1, dar;
int r;
p=&buf[l-1];
r=0;
while(p>=buf){
da1=*p-'0';
dar=(da1<<1)+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
memmove(&buf[1], buf, strlen(buf)+1);
*buf='1';
}
}
void stringBaseInc(char *buf, int base){
char *p;
int l=strlen(buf);
int da1, dar;
int r;
p=&buf[l-1];
r=1;
while(p>=buf && r){
da1=*p-'0';
dar=da1+r;
r=(dar>=base)? 1: 0;
*p='0'+(dar%base);
--p;
}
if(r){
memmove(&buf[1], buf, strlen(buf)+1);
*buf='1';
}
}
void stringLongLongInt(char *buf, unsigned long h, unsigned long l, int base){
unsigned long init=l;
int s=0, comb=0;
if(h){
comb=1;
init=h;
while(!(init&0x80000000L)){
init<<=1;
init|=(l&0x80000000L)? 1: 0;
l<<=1;
s++;
}
}
buf[0]='0';
buf[1]=0;
stringBaseAdd(buf, init, base);
if(comb){
l>>=s;
h=0x80000000L>>s;
s=sizeof(l)*8-s;
while(s--){
stringBaseDouble(buf, base);
if(l&h)
stringBaseInc(buf, base);
h>>=1;
}
}
}
If you ask for
char buff[20];
stringLongLongInt(buff, 1, 0, 10);
your buff will contain 4294967296

Resources