Live data from Hacker News

22nd Century C

procedural.github.io

21–30 of 106 posts

Re: 22nd Century C

#21
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

C's normal integer types work the closer to the way you want. When you say you're returning an int, you're not really specifying the exact size at all.

For those who don't know, C's char, short, int and long data types aren't really "fixed size". The standard defines their order: sizeof(char) Now you may be thinking "sure the standard says they could be different, but they aren't really, a char is 8bit, a short is 16-bit an int is 32-bit a long is 64-bit". So here's a couple examples for you: many DSP platforms have a C compiler where char is 16-bit. Also Microsoft Visual c++ on windows on x86_64 compiles longs as 32-bit while GCC on Linux on x86_64 compiles longs as 64-bits.

>Notice how smooth the 32-bit to 64-bit transition went? (and yes, it was smooth.)

I know you said it was smooth, and maybe it was for some applications. But for many others, the 32-bit to 64-bit transition actually caused a lot of problems! Andrey Karpov has already done a great job of categorizing many of them, so I won't waste my time repeating him, but you can read his list here: http://www.viva64.com/en/a/0065/

Re: 22nd Century C

#22
post #21
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

C's normal integer types work the closer to the way you want. When you say you're returning an int, you're not really specifying the exact size at all. For those who don't know, C's char, short, int and long data types aren't really "fixed size". The standard defines their order: sizeof(char) Now you may be thinking "sure the standard says they could be different, but they aren't really, a char is 8bit, a short is 16…

Yeah, I'm arguing that the situation you describe (accurately) is better than baked-in sizes all over the source code.

Use the platform-native types (whatever size they may be) unless you have a reason not to, then use or an analogue. If CHAR_BIT is 13, let char be 13 bits: the platform probably chose that for a reason. When you have to pack it into a TCP header, do your strict fixed-width stuff there.

Re: 22nd Century C

#23
post #12
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

Looks like you haven't worked on embedded systems. We need to be very careful with sizes of ints here. Not just because we run the risk of overflows, but also because when we create code that may have to be ported from one architecture to another, we want to minimize re-work. > Notice how smooth the 32-bit to 64-bit transition went? There are many reasons for that. For most PC work, a 32-bit int is more than large en…

I work with embedded systems daily, writing code that is expected to work on multiple different architectures (e.g. systems where char is 8-bit, 16-bit, 24-bit or 32-bit, systems without floating point units, systems with SIMD instructions, systems without, etc). In doing this, I have found that fixed width types make the job harder, and any code that uses fixed width types is generally more difficult to work with.

You have an int16_t? How do you port it to a machine without a 16-bit type? What would happen if you replaced it with a 32-bit type? If you are relying on wraparound, then your code is already undefined, so some compiler is likely going to mess with you anyway.

The stuff about communicating with the outside world is quite different. At this point you have protocols, and it depends on how a protocol is written, and how you are able to actually interact with the world to fulfil that protocol. If the protocol is an ABI, then generally you are fine, because the compiler too will match the ABI. If it is a file format, then you need to know how your file io functions work (do they just write the bottom 8-bits of a char, or do they blat the whole thing across?).

Re: 22nd Century C

#24
post #21
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

C's normal integer types work the closer to the way you want. When you say you're returning an int, you're not really specifying the exact size at all. For those who don't know, C's char, short, int and long data types aren't really "fixed size". The standard defines their order: sizeof(char) Now you may be thinking "sure the standard says they could be different, but they aren't really, a char is 8bit, a short is 16…

This is basic knowledge for C programmers.

I believe the parent was positing that the relative sizes you desribe are better than fixed sizes, and as a systems programmer I'm inclined to agree.

Re: 22nd Century C

#25
post #15

Too little too late. Rust is already taking over, by the 22nd century C will be dead.

There will probably be C code running in 2100. That's only 84 years away. FORTRAN is now 60 years old and still going strong in scientific computing. (Partly because, in most other languages, multidimensional array support is worse.) I suspect, though, that new successful languages will have automatic memory management, either GC/reference counting or Rust-type borrow checking. There's no reason for a new language wi…

Dlang is actually quite nice and mature, although nowhere nearly as hyped as Rust, Go or Swift. You get a GC with the option of deactivating it and doing the memory management yourself, pointers and casts if you need them (you usually don't), an auto type, fast compiling times, among many other cool things.

https://dlang.org/overview.html

Re: 22nd Century C

#26

Too little too late. Rust is already taking over, by the 22nd century C will be dead.

I don't know what the systems programming language of the 22nd century will look like, but I do know that it will be called C.

Re: 22nd Century C

#27
That is very impressive. I really like the cleverness and cleanliness of these "hacks".

Still... I wouldn't introduce it into existing/shared codebase due to risk of confusing everyone, and I will never start my own project in C again.

Re: 22nd Century C

#28
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

So you really have two arguments in there. For pointers, I'm sure no one will disagree that size_t is a good thing. Which is why any modern low-level language has these built-in.

As for fixed size types, what are the alternatives? If you wanted a dynamically sized int, you'd either need to reserve all the possible space you'd need (in which case why not just use a int64_t), or you'd need some kind of heap-allocated integer that can resize itself. We can't hide the fact that the machine itself uses fixed-size ints, unless we are willing to live with a leaky abstraction.

Re: 22nd Century C

#29
post #9

I've spent two decades writing C and C++, but the last 8-9 years in really high-level languages (Ruby, Javascript, Python). From either end of the spectrum, I've never felt the need for such emphasis on fixed-sized numeric types. I've commonly needed access to fixed size numerics, like when sending texture formats to the GPU, defining struct layout in file formats and network protocols, but I have never once thought:…

Overflow is often something kept in mind in careful C programming. It's something you don't have to worry about nearly as much in Python (promotes to bignum) or Javascript (double precision float).

That 32 to 64 bit transition? Windows couldn't change the size of "long" because it would break too much windows software that assumed long was 4 bytes. Thus "long long".

The Linux ecosystem fared a bit better because of the greater variety of Unix systems and cross-platform C that ran on them. It was a time of fragmentation and incompatibility, but also a time of posix and attempting to define minimal standards in a portable and flexible way. Windows of course didn't have to care about any of that.

I actually fixed some old-ish classic open source networking software for 64-bit mips, around 2010. You see, it worked OK on x86_64, which is little endian, because in that case the low-order 4 bytes (an ipv4 address) end up in the same place relative to the start address, whether it's a 4-byte or 8-byte type. But for big-endian 64-bit mips, that doesn't work out, the low-order 4 bytes are on the unlucky end of the 8-byte type.

There's also the awkwardly named "ntohl()" and "htonl()" standard library functions that were named in the distant past when it was assumed a long would always be 4 bytes. As soon as that wasn't true they changed to work with uint32_t, as they always should have.

Sure, I'll use a plain int whenever I'm returning a status or error code, and whenever iterating over some trivial range. I'll use a "char[]" or similar for a string of ascii. But for many things, like "count of bytes transferred", or "seconds until timeout", or any meaningful quantity value or anything stored in a struct (meaningful and non-transient), I'll pick the appropriate bit-size, to make the code clear. It's good style because you have to know the limits of the type whenever you do anything non-trivial with it.

These days, there's always a value here or there where 4 billion will sometimes not be enough: bytes, microseconds. I need 64 bits. I could write "long long", but why not write what I really mean: "uint64_t" aka give me 64 bits.

(also, "unsigned" is longer to write and read :)

Re: 22nd Century C

#30
post #22
post #21

Earlier quoted context omitted.

C's normal integer types work the closer to the way you want. When you say you're returning an int, you're not really specifying the exact size at all. For those who don't know, C's char, short, int and long data types aren't really "fixed size". The standard defines their order: sizeof(char) Now you may be thinking "sure the standard says they could be different, but they aren't really, a char is 8bit, a short is 16…

Yeah, I'm arguing that the situation you describe (accurately) is better than baked-in sizes all over the source code. Use the platform-native types (whatever size they may be) unless you have a reason not to, then use or an analogue. If CHAR_BIT is 13, let char be 13 bits: the platform probably chose that for a reason. When you have to pack it into a TCP header, do your strict fixed-width stuff there.

I completely agree with you when it comes to function return types.

For data structure fields, especially structs used many, many times like in very large arrays, I'd say it's sometimes worth using fixed size types to get better control over memory use. Using a 64-bit int for a field a 16-bit integer can handle will use up 4x as much memory. And if you've got a ten or a hundred million structs of that type, then it really adds up.

For example size_t is 64-bit on my x86_64 system. But modern x86_64 systems can only use 48-bit address spaces, so a 64-bit sized object can't even be addressed! Even worse is my cpu and motherboard have a 32gb maximum of RAM (for an effective 35-bit physical addressing limitation). And size_t is supposed to be able to store the size of any object in memory, but on this platform it stores things that won't fit in memory. So most of these 64-bits are wasted on modern systems. For files you can use off_t if you're on POSIX, but the C standard doesn't say anything about requiring size_t to be able to store any filesize in a filesystem.

Just using size_t is not enough to make your code work correctly on 64-bit size quantities either. For example, you make your strlen implementation return size_t, and you use size_t everywhere you do anything with a string. But can your application really handle strings that are bigger than the system RAM , or the hardware address space? Are your algorithms even efficient enough to handle the 4,294,967,295 byte maximum string size for a 32-bit system?

The effort to get your program to work efficiently on >32-bit quanities is often much harder than just using size_t instead of int.

So to me, when I see 64-bit size_ts being used everywhere in code that won't actually be able to handle working with >32-bit quantities, it just feels a little useless. Of course this is really more a complaint about how big size_t is on the x86_64 platform than it is a complaint about the idea of size_t in general. If only we had 48-bit size_ts (24-bit would be handy too!)

Post reply on HN