News for hackers. Stuff that matters.
Re:Comp.lang.c Frequently Asked Questions by SavantIdiot on Sunday September 12, 2021 @01:05PM (#28502855)
1.1. How should I decide which integer type to use?

Programmer: Hmmm, I think these three should be shorts and these 10 can fit in chars.

Modern compiler: Fuck that, you're all 32-bits. I ain't got time for unaligned memory access...

Re:Comp.lang.c Frequently Asked Questions by sdfdf4434r34r on Sunday September 12, 2021 @02:29PM (#28503559)
And then you get to the unfortunate situation that is the x64 ABIs - int is still 32-bit, leading to a bunch of extra movsx instructions if you use ints for things like indexing.
Re:Comp.lang.c Frequently Asked Questions by WalterBright on Sunday September 12, 2021 @02:46PM (#28503667)
Use size_t to declare anything that will be used as an index.
Re:Comp.lang.c Frequently Asked Questions by SavantIdiot on Sunday September 12, 2021 @02:56PM (#28503758)
This is literally the reason `size_t` was created.
Re:Comp.lang.c Frequently Asked Questions by jstanley on Sunday September 12, 2021 @04:15PM (#28504481)
Why isn't it called index_t then?
Re:Comp.lang.c Frequently Asked Questions by burnished on Sunday September 12, 2021 @05:40PM (#28505263)
As a fellow student of "why is this named that, what does this name mean" I have found that asking about counterfactuals is rarely satisfying. Naming stuff is hard and the question assumed a level of intent that I think is rarely present. Asking "how did this thing get named that" works out better, cause it seems that occasionally gets written down.
Re:Comp.lang.c Frequently Asked Questions by jstanley on Sunday September 12, 2021 @05:51PM (#28505356)
My point was that it seems more likely that size_t was created to represent sizes than to represent indexes.

I don't disagree that size_t is an appropriate type for indexes, but I don't think indexes are literally the reason it was created.

Re:Comp.lang.c Frequently Asked Questions by tialaramex on Sunday September 12, 2021 @06:58PM (#28505854)
It's named for sizeof, a C operator which returns a positive integer but annoyingly the core C language itself doesn't define what the type of that integer is, the standard library does though, naming it size_t

Now, sizeof does measure the size of things, but, one of the obvious sizes you can measure is an array†, and that's definitely also the maximum index value for the array, so I do think it's fair to say that's (part of) literally why size_t exists.

† One of C's treacherous footguns. In the scope where the array was defined it's an array, and sizeof(array) tells you how big that array is. But, passed as a parameter it becomes a pointer and sizeof(resulting_pointer) is the size of the pointer, not the array :(

Re:Comp.lang.c Frequently Asked Questions by Thorrez on Monday September 13, 2021 @01:21AM (#28508092)
>Now, sizeof does measure the size of things, but, one of the obvious sizes you can measure is an array†, and that's definitely also the maximum index value for the array

Make sure to be careful and realize that sizeof my_array returns the number of bytes that my_array uses, not the number of elements. An array of 10 ints likely has sizeof == 40, while indexing past 9 would be undefined behavior.

Re:Comp.lang.c Frequently Asked Questions by tialaramex on Monday September 13, 2021 @04:03AM (#28508945)
Excellent point, that largely contradicts my earlier position in fact. I was thinking of an array of chars and should have considered that's only a special case.
Re:Comp.lang.c Frequently Asked Questions by _kst_ on Sunday September 12, 2021 @09:49PM (#28507014)
The core language says that the result of sizeof is size_t, defined in <stddef.h> (and other headers).

size_t is a typedef (alias) for an implementation-defined unsigned integer type.

It could have been worded differently with the same meaning. For example, the core language (section 6 of the standard) could have said that sizeof yields a result of an implementation-defined unsigned integer type without referring to "size_t". The library section (section 7) already says that size_t "is the unsigned integer type of the result of the sizeof operator". Personally I think that referring to size_t in the language section adds clarity, even if it's slightly redundant.

In a given implementation, a compiler might arrange for sizeof to yield a result of type unsigned long, for example. The corresponding <stddef.h> header must then define size_t as unsigned long for the implementation to be correct.

Re:Comp.lang.c Frequently Asked Questions by burnished on Sunday September 12, 2021 @09:36PM (#28506940)
Well, my point is that "more likely" and "more reasonable" are rarely reasons why things were done in the first place so using the benefit of hindsight to try and suss out cause and effect will frequently lead you to plausible but incorrect answers (specifically for the history and naming of things).

Then again, being wrong about something seems faster than asking a question, and this little thread has already unearthed interesting answers, so maybe you have the right of it!

Re:Comp.lang.c Frequently Asked Questions by Thorrez on Monday September 13, 2021 @01:17AM (#28508068)
I agree and disagree. Yes it was created for size. But when indexing std::vector you can index up to the size, and thus should use the same type for both.
Re:Comp.lang.c Frequently Asked Questions by SAI_Peregrinus on Sunday September 12, 2021 @06:10PM (#28505505)
Because C doesn't really have indexes, it has pointers and offsets. offset_t would make more sense than index_t.
Re:Comp.lang.c Frequently Asked Questions by ohazi on Sunday September 12, 2021 @07:07PM (#28505930)
There's also ssize_t and ptrdiff_t for offsets that might be negative. Use is pretty nuanced, read the docs before using, etc.
Re:Comp.lang.c Frequently Asked Questions by SAI_Peregrinus on Sunday September 12, 2021 @08:40PM (#28506619)
And intptr_t and uintptr_t for results of computations resulting in pointers. Sadly C's type system isn't really powerful enough to properly take advantage of these.
Re:Comp.lang.c Frequently Asked Questions by jamesfinlayson on Sunday September 12, 2021 @08:48PM (#28506665)
I think the next (or current - I've lost track) version of C++ has an idx_t type which is an unsigned int of some sort, which will be the recommended type for for loops.
Re:Comp.lang.c Frequently Asked Questions by _kst_ on Sunday September 12, 2021 @10:21PM (#28507206)
I don't see a reference to "idx_t" anywhere in the latest draft of the C++ standard.
Re:Comp.lang.c Frequently Asked Questions by jamesfinlayson on Monday September 13, 2021 @01:02AM (#28508020)
Yep, I can't find anything either - I thought I read it four or five years ago in an interview with someone big in the C++ community.
Re:Comp.lang.c Frequently Asked Questions by marcthe12 on Monday September 13, 2021 @12:59AM (#28508003)
Because its the return type of the sizeof operator
Re:Comp.lang.c Frequently Asked Questions by saagarjha on Sunday September 12, 2021 @01:14PM (#28502925)
Modern compilers generally prefer register-sized data.
Re:Comp.lang.c Frequently Asked Questions by SavantIdiot on Sunday September 12, 2021 @01:16PM (#28502938)
Ah thanks, that's what I was thinking. But somehow I got caught up in unaligned cacheline accesses, which are much larger than 32-bits. It's early where I am. :)
Re:Comp.lang.c Frequently Asked Questions by masklinn on Sunday September 12, 2021 @02:40PM (#28503633)
I mean there are 4 different concepts at play here:

Unaligned memory access, types generally have an alignment which is the same as their length and structs have the alignment of their largest member because many architectures get quite cross with unaligned access e.g. trying to load a 32b integer from memory to register while it's not aligned to 32b, this is where compilers will pad structures to ensure everything is aligned properly by default, and where (in C/C++ anyway) you want to take care of your struct layout to avoid unnecessary padding. That doesn't prevent "these three should be shorts and these 10 can fit in chars." at all, but if you intersperse them the structure will increase in size due to padding.

Then there's C being specified in terms of lowest capabilities so while "char" and "short" are at least 8 and at least 16 bits… they can also be larger (POSIX does specify that char must be exactly 8 bits but non-POSIX platforms don't require that). That matches everything being 32b. It's a somewhat common occurrences for DSPs to have char of 16 or 32 bits, it really has nothing to do with the compiler (except insofar as the compiler does what the architecture description specifies).

Then there's the preferred data size, which is probably a function of the architectural ALUs than the native registers e.g. if an architecture only works on 32b datum then computations on 8 bit data will require loading 8 bits, zeroing the upper 24, performing the computation in 32b, copying whichever bit is concerned to the overflow flag, then zeroing that. Whereas performing the computation on a 32b-native type would require loading 32b, performing the computation, done (that was never a concern on x86/64 but IIRC older revisions of ARM could only natively work in 32b, and not all possible arithmetic operations got expanded to 8/16b at the same time).

And finally there's the cache line alignment. There are actually two opposite issues with cacheline alignments: you usually want your structure to not span cachelines (as that gets more expensive) but sometimes you want your structures be always start at the start of a cacheline (and possibly take the entirety of the cacheline) to avoid false sharing issues: if two unrelated structures are on the same cache line and they're used from different cores, the cores will need a lot more synchronisation than if they were on different cache lines.

Re:Comp.lang.c Frequently Asked Questions by joatmon-snoo on Monday September 13, 2021 @02:10AM (#28508296)
cache alignment also gets stupid complicated when you add in what kind of malloc you use, c.f. google's tcmalloc: https://github.com/google/tcmalloc