English Amiga Board

English Amiga Board (https://eab.abime.net/index.php)
-   Coders. C/C++ (https://eab.abime.net/forumdisplay.php?f=118)
-   -   LONG not big enough (https://eab.abime.net/showthread.php?t=73825)

mritter0 25 May 2014 00:12

LONG not big enough
 
1 Attachment(s)
I am trying to get a harddrives free space. I can do it just fine, but I can't store the size correctly. LONG is not big enough; 4GB max.

LONG freeBytes=64016611328; (just to show an example size) (60GB)

double or float is what I need, correct? The size could be over 1TB.

But now I can't display it with sprintf()

sprintf(buffer,"Free Space: %f",freeBytes);

just prints the %f when display buffer.

Can't the SAS/C (OS3.9) sprintf() handle floats and doubles? There will never be a decimal point. Is there some other method I need to use?

In the image below, Size number blocks * 512 = 64016611328

hooverphonique 25 May 2014 01:00

you cannot format an integer type with %f..

maybe sas supports 'long long' ?

thomas 25 May 2014 11:57

This is a stupid aproach. Nobody wants the read the number of bytes of a harddrive if its size is measured in 10s of gigabytes.

Even megabytes are too much, but nevertheless you can use this to show megabytes:

Code:

long blksize  = InfoData->id_BytesPerBlock;
long blksfree = InfoData->id_NumBlocks - InfoData->id_NumBlocksUsed;

Printf ("free space: %ld MB\n",blksfree / (1024*1024 / blksize));


mc6809e 25 May 2014 12:59

Looks like you're just going to have to write a base 2^32 (or base 65536 or base 256) to base 10 conversion routine and construct the output string digit by digit.

Nearly trivial.

mritter0 25 May 2014 22:22

@Thomas: As always, thanks for the pointer. But, no, I wasn't going to display the total bytes to the user. I first tested it on a small 2.5GB partition, then a floppy. It worked. Then tried the large partition, numbers all messed up. I wanted to see what was going on so I tried to display it in a requester. Then it dawned on me it was too large of a number. Sorry for trying to figure it out in a more visual manner.

Lonewolf10 25 May 2014 23:52

Quote:

Originally Posted by mritter0 (Post 956303)
@Thomas: As always, thanks for the pointer. But, no, I wasn't going to display the total bytes to the user. I first tested it on a small 2.5GB partition, then a floppy. It worked. Then tried the large partition, numbers all messed up. I wanted to see what was going on so I tried to display it in a requester. Then it dawned on me it was too large of a number. Sorry for trying to figure it out in a more visual manner.

You shouldn't apologise for that, if I can't work what's going on I always display the variables onscreen that I think are related to any issue/s I might be having. Of course, forgetting to remove them is an occasional downside, but it's something that can be fixed easily :)

BigFan 26 May 2014 10:39

If you ever go nuts about your code,
#define DEBUG

and put some lines inside

ifdef DEBUG
printff(format, var,..)
endif

removing with undef DEBUG or comment it out. Debug output will be supessed then.

?? Did you try to print your long var as this:

sprintf(buffer,"Free Space: %ld",freeBytes);

On some older compilers the printf family may fail to output formatted long(or anything bigger than int). In that rare case you need to convert them with ltoa() if available or do it with your own little conversion routine.

phx 26 May 2014 15:24

Quote:

Originally Posted by mritter0 (Post 956127)
LONG freeBytes=64016611328; (just to show an example size) (60GB)

double or float is what I need, correct? The size could be over 1TB.

IIRC SAS/C 6.x doesn't support 64 bit integer (long long), so this is indeed the only possibility, besides writing your own high-precision conversion routine, as mc6809 indicated.


Quote:

sprintf(buffer,"Free Space: %f",freeBytes);

just prints the %f when display buffer.
You forgot to link with the math library.

Usually the printf in the clib only supports integer. It has to be replaced by the float-enabled printf frome the math library.

thomas 26 May 2014 15:52

You could store the size in kilobytes. This would extend your range from 4GB to 4TB.

mritter0 26 May 2014 19:41

Using flags MATH=STANDARD and PRECISION=MIXED. I was linking LIB:scm.lib. Without it I was getting link errors. Also tried with LIB:scmieee.lib. Same result.

I always use %ld in my sprintf() calls. With that it comes out a negative value (with ULONG). That is what got me started on this.

I don't really need to "see" the total bytes, it was just a "WTF is going on?" moment.

With Thomas' code I got started. I was just hoping to use double or float to get a deicmal like "59.5 GB". Maybe with the basic math functions I can still do it.

Thanks for the help, guys.

thomas 26 May 2014 22:01

You can use something like this:

Code:

char *nice_size (char *buffer,unsigned long blksize,unsigned long numblks)

{
unsigned long bpg = 1024*1024*1024 / blksize;        /* blocks per gigabyte */
unsigned long bpm =      1024*1024 / blksize;        /* blocks per megabyte */
unsigned long size;
char *unit;

if (numblks >= bpg)
        {
        size = (numblks / bpm * 100 + 512) / 1024;
        unit = "GB";
        }
else if (numblks >= bpm)
        {
        size = (numblks * blksize / 1024 * 100 + 512) / 1024;
        unit = "MB";
        }
else
        {
        size = numblks * blksize;
        if (size >= 1024)
                {
                size = (size * 100 + 512) / 1024;
                unit = "KB";
                }
        else
                {
                sprintf (buffer,"%lu Bytes",size);
                return (buffer);
                }
        }

sprintf (buffer,"%lu.%02lu %s",size / 100,size % 100,unit);
return (buffer);
}


mritter0 27 May 2014 02:03

I wrote something pretty much just like that, but my math was off. So switched to yours.

Just for the sake of it, I added this for terabytes:
Code:

        if (NumBlocks>=bpg)
        {
                size=(NumBlocks/bpm*100+512)/1024;
                unit="GB";

                if (size>=100000)
                {
                        size=(size*100+512)/1024;
                        unit="TB";
                }
        }
        else if (NumBlocks>=bpm)

I don't have a terabyte drive to test it on, but looks correct.

thomas 27 May 2014 11:25

Two notes:

1. my routine works with binary megabytes (sometimes also called mebibytes). So your check for terabytes (tebibytes) should by if (size >= 102400).

If you want to work with decimal megabytes, you should replace all occurences of 1024 by 1000 and 512 by 500.

2. nobody yet has proven whether advanced format harddrives (i.e. with 4096 byte blocks) will work on AmigaOS 3.x. Therefore you probably won't ever see a drive bigger than 2TB. So the check for terabytes might be overkill.

BigFan 27 May 2014 11:55

1 Attachment(s)
I've installed SAS/C yesterday. Oh my god, that reminds me of a horrible experience when buying an introduction into asm that came with seka on floppy disc those days. SAS editor is hardcoded to key codes? No support for foreign layouts?

Having a quick peek in limits.h shows that there is no support for >32bit.
Long and Int are same size.

If you really need large numbers/adresses consider using a more modern compiler like vbcc or the like.

You can always ask your compiler what's the max size of each type.

E.g.:
Code:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>


/* #define VBCC*/

int main(void)
{
#ifdef VBCC
    unsigned long long  myval = 6123456789L;
    printf("Big value %llu \n", myval);
#endif
    printf("size of unsigned int \t\t %u \n", UINT_MAX);
    printf("size of unsigned long \t\t %lu \n", ULONG_MAX);
#ifdef VBCC
    printf("size of unsigned long long \t %llu \n", ULLONG_MAX);
#endif
return 0;
}

Compiled binary in attachement

Edit: when compiling with vbcc uncomment define and use -c99 as option.

phx 27 May 2014 13:02

Quote:

Originally Posted by BigFan (Post 956558)
Code:

    unsigned long long  myval = 6123456789L;

A small note: the 'L' suffix would usually make it a "long" constant. "long long" needs LL.

But in most cases, like the one above, you don't need such a suffix, as the type is clear to the compiler. When assigning a long long variable the constants default to long long as well. So it works here, because the 'L' is ignored.

Cherno 27 May 2014 15:04

Quote:

LONG not big enough
That's what she said... Oh well. I'll go get my coat.

http://d3na4zxidw1hr4.cloudfront.net...30x328_q85.jpg

mritter0 28 May 2014 00:52

I haven't had time to do a full test, but I noticed that when doing RAM, it is one level higher (GB instead of MB). I think it is because the block size is 1024. Any idea on that?

BigFan 28 May 2014 21:37

Code:

        if (NumBlocks>=bpg)
        {
                size=(NumBlocks/bpm*100+512)/1024;
                unit="GB";

                if (size>=102400)
                {
                        size=(size*100+512)/1024;
                        unit="TB";
                }
        }
        else if (NumBlocks>=bpm)

Still this code is buggy. Look, size has been already made "division proof".

Code:

size = size / 1024;
would be better or you need to alter printf() to use other modulo than 100.

mritter0 30 May 2014 02:01

Not sure what you mean by that.

Either way, after some tweaking and additions to handle RAM in a different way (AvailMem()), it is all working good.

thomas 30 May 2014 10:43

Quote:

Originally Posted by mritter0 (Post 957032)
Not sure what you mean by that.

Your code prints 100 TB instead of 1 TB.


Quote:

Originally Posted by mritter0 (Post 956516)
I don't have a terabyte drive to test it on, but looks correct.

You should use a test driver like this one:

Code:

int main (int argc,char **argv)

{
char buffer[20];

if (argc != 3)
        {
        printf ("invalid args\n");
        return (20);
        }

printf ("%s\n",nice_size(buffer,atoi(argv[1]),atoi(argv[2])));

return (0);
}


Result:

Code:

3> nice_size 512 2147483647
100.00 TB
3>



All times are GMT +2. The time now is 03:36.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.

Page generated in 0.04628 seconds with 11 queries