www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Basic question about size_t and ulong

reply WhatMeWorry <kheaser gmail.com> writes:
Quoting the D documentation:

size_t is an alias to one of the unsigned integral basic types, 
and represents a type that is large enough to represent an offset 
into all addressable memory.  And I have a line of code:

size_t huge = ulong.max;

dmd GC.d
GC.d(29): Error: cannot implicitly convert expression 
`18446744073709551615LU` of type 'ulong` to `uint


Isn't ulong an integer? And isn't memory addresses 64 bits long?

size_t huge = uint.max;  // compiles

works but now I'm just curious.  I was just seeing what is the 
largest dynamic array I could create.
Mar 18 2022
next sibling parent Adam Ruppe <destructionator gmail.com> writes:
On Friday, 18 March 2022 at 21:54:55 UTC, WhatMeWorry wrote:
 Isn't ulong an integer? And isn't memory addresses 64 bits long?
Only if you are doing a 64 bit build. Try using -m64
Mar 18 2022
prev sibling parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/18/22 14:54, WhatMeWorry wrote:

 size_t is an alias to one of the unsigned integral basic types, and
 represents a type that is large enough to represent an offset into all
 addressable memory.
In practice, that general description means "size_t is either ulong or uint" depending on your platform (or build e.g. -m32 as Adam said).
 size_t huge = uint.max;  // compiles
That means size_t is uint on that build. Ali P.S. On a related note, I used to make the mistake of using size_t for file offsets as well. That is a mistake because even on a 32-bit system (or build), file sizes can be larger than uint.max. So, the correct type is long for seek() so that we can seek() to an earlier place and ulong for tell().
Mar 18 2022
next sibling parent Steven Schveighoffer <schveiguy gmail.com> writes:
On 3/18/22 7:01 PM, Ali Çehreli wrote:
 On 3/18/22 14:54, WhatMeWorry wrote:
  > size_t huge = uint.max;  // compiles
 
 That means size_t is uint on that build.
Not that Ali is wrong in the full sense, but this line alone will compile on both 64 and 32-bit systems, so it is not informative. However, the fact that assigning it to `ulong.max` doesn't work coupled with this means that it's 32-bit. You can use code like this to tell you what your platform bits are: ```d pragma(msg, cast(int)(size_t.sizeof * 8), " bit"); ``` -Steve
Mar 21 2022
prev sibling parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Friday, 18 March 2022 at 23:01:05 UTC, Ali Çehreli wrote:
 P.S. On a related note, I used to make the mistake of using 
 size_t for file offsets as well. That is a mistake because even 
 on a 32-bit system (or build), file sizes can be larger than 
 uint.max. So, the correct type is long for seek() so that we 
 can seek() to an earlier place and ulong for tell().
Perhaps we should back up and ask a different question. I've been working on adaptation of Reed Solomon Codes, and i keep getting thrown with casting errors, to the point where i just want to make everything size_t to make the errors go away. So when should you use size_t? Is it better to use int, long, size_t? Or is it better to try to use the smallest type you need that will fulfill the function's needs and just add to handle issues due to downcasting?
Mar 22 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 3/22/22 11:28, Era Scarecrow wrote:

   So when should you use size_t?
I use size_t for anything that is related to count, index, etc. However, this is a contested topic because size_t is unsigned. As soon as you use it in an expression, the whole expression becomes unsigned as well. (Related: Usual Arithmetic Conversions at the link below.) For that reason, at least during an "ask us anything" session at a C++ conference, where Andrei was among the panel, Herb Sutter and others agreed that it was a mistake to choose unsigned for size_t. So far, I didn't have much trouble from that decision. I am always careful when subtracting two size_ts.
 Is it better to use int, long, size_t?
D uses size_t for automatic indexes during foreach, and as I said, it makes sense to me. Otherwise, I think the go-to type should be int for small values. long, if we know it won't fit in an int.
 Or is it better to try to use the smallest type you need that will
 fulfill the function's needs and just add to handle issues due to
 downcasting?
That may be annoying, misleading, or error-prone because smaller types are converted at least to int in expressions anyway: https://dlang.org/spec/type.html#integer-promotions (Every D programmer should know the whole section 6.4 there.) But yeah, if your function works on a byte, sure, it should take a byte. Expect wild disagreements on this whole topic. :) Ali
Mar 22 2022
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 22 March 2022 at 18:47:19 UTC, Ali Çehreli wrote:
 On 3/22/22 11:28, Era Scarecrow wrote:
   So when should you use size_t?
I use size_t for anything that is related to count, index, etc. However, this is a contested topic because size_t is unsigned.
I don't see a problem with that. It's not like you can access -300 address space or index (*although making your own index function technically you could*). I'm actually surprised signed is the default rather than unsigned. Were negative numbers really that important in 16bit MS-DOS that C had to have signed as the default? This question is probably going off topic but still be interesting to know if there's an answer.
 Is it better to use int, long, size_t?
D uses size_t for automatic indexes during foreach, and as I said, it makes sense to me. Otherwise, I think the go-to type should be int for small values. long, if we know it won't fit in an int.
Mhmm. More or less this is what i would think. I'm just getting sick of either numbers i return that i have to feed into indexes and it complains it's too big, or putting what is going to be a smaller number in an array because the array type is too small. Casting or using masks may resolve the issue, but it may crop up again when i make a change or try to compile on a different architecture. My usual writing at this time is doing my work on a 64bit laptop, but sometimes i go and run the 32bit dmd version in windows on a different computer and checking for differences between ldc/gdc and dmd for if the code complains. I see more and more why different versions of compilers/OSes is a pain in the ass. I'd almost wish D had a more lenient mode and would do automatic down-casting, then complain if it *would* have failed to downcast data at runtime.
 Or is it better to try to use the smallest type you need that 
 will fulfill the function's needs and just add to handle 
 issues due to downcasting?
That may be annoying, misleading, or error-prone because smaller types are converted at least to int in expressions anyway:
Yeah, and i remember reading about optimization in GCC where doing smaller types can actually be slower, much like in some architectures having offsets in memory address results in a speed penalty for non-aligned data.
 But yeah, if your function works on a byte, sure, it should 
 take a byte.

 Expect wild disagreements on this whole topic. :)
Though internally it may be an int...
Mar 22 2022
parent reply "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
On Tue, Mar 22, 2022 at 09:11:00PM +0000, Era Scarecrow via Digitalmars-d-learn
wrote:
[...]
 I'd almost wish D had a more lenient mode and would do automatic
 down-casting, then complain if it *would* have failed to downcast data
 at runtime.
[...] We already have this: import std.conv : to; int x; long y; y = x.to!long; // equivalent to straight assignment / cast x = y.to!int; // throws if out of range for int T -- Gone Chopin. Bach in a minuet. I see that you JS got Bach.
Mar 22 2022
parent reply Era Scarecrow <rtcvb32 yahoo.com> writes:
On Tuesday, 22 March 2022 at 21:23:43 UTC, H. S. Teoh wrote:
 On Tue, Mar 22, 2022 at 09:11 PM, Era Scarecrow wrote:
 [...]
 I'd almost wish D had a more lenient mode and would do 
 automatic down-casting, then complain if it *would* have 
 failed to downcast data at runtime.
 [...]
We already have this: import std.conv : to; int x; long y; y = x.to!long; // equivalent to straight assignment / cast x = y.to!int; // throws if out of range for int
At which point I might as well just do cast(int) on everything regardless **BECAUSE** the point of it is **NOT** having to add a bunch of conversions or extra bits to it. This particular usage can be useful, just not in the *automatic* sense i was meaning.
Mar 22 2022
parent Era Scarecrow <rtcvb32 yahoo.com> writes:
On Wednesday, 23 March 2022 at 00:51:42 UTC, Era Scarecrow wrote:
 On Tuesday, 22 March 2022 at 21:23:43 UTC, H. S. Teoh wrote:
 We already have this:

 	import std.conv : to;
 	int x;
 	long y;
 	y = x.to!long;	// equivalent to straight assignment / cast
 	x = y.to!int;	// throws if out of range for int
This particular usage can be useful, just not in the *automatic* sense i was meaning.
Forgot to add this; for the more automatic mode maybe add a new tag say autodowncast, which may add the .to!passingtype leaving said checks without needing to throw casts in a dozen places. Though i doubt Walter or Andrei would go for it.
Mar 22 2022