Live data from Hacker News

Some C habits I employ for the modern day

unix.dog

91–100 of 162 posts

Re: Some C habits I employ for the modern day

#91

> and I end up having all these typedefs in my projects I avoid doing this now. It's more trouble than it's worth and it changes your code from a standard dialect of C into a custom one. Plus my eyes are old and they don't enjoy separating short identifiers. > typedef struct { ... } String I avoid doing this. Just use `struct string { ... };'. It makes it clear what you're handling. C23 finally gave us "auto", you sh…

> So you use strlen() a lot and don't have to deal with multibyte characters anywhere in your code. It's not much of a strategy. You don't need to support all multibyte encodings (i.e. DBCS, UCS-2, UCS-4, UTF-16 or UTF-32) characters if you're able to normalise all input to UTF-8. I think, when you are building a system, restricting all (human language) input to be UTF-8 is a fair and reasonable design decision, and…

> I think, when you are building a system, restricting all (human language) input to be UTF-8 is a fair and reasonable design decision, and then you can use strlen to your hearts content.

It makes no sense. If you only need the byte count then you can use strlen no matter what the encoding is. If you need any other kind of counting then you don't use strlen no matter what the encoding is (except in ASCII only environment).

"Whether I should use strlen or not" is a completely independent question to "whether my input is all UTF-8."

Re: Some C habits I employ for the modern day

#92
post #84

Earlier quoted context omitted.

People that contribute to WG14 are naturally biased against C++, especially with gimmicks like _Generic. Internet is full of people asserting CVEs in C are only caused by not skilled enough devs.

> Internet is full of people asserting CVEs in C are only caused by not skilled enough devs. Sure, but those people are not here, and usually aren't on HN anyway. The internet is also full of people asserting that CVEs in C++ are only caused by not skilled enough devs, but I consider those people irrelevant too. The reasons for rejecting C++ in this forum have been repeated often enough that you should have seen them…

Yeah the same reasons as the flamewars on comp.lang.c and comp.lang.c++.

WG21 could do a better job, but that least they acknowledge security has to be tackled somehow.

Re: Some C habits I employ for the modern day

#94
post #88

Earlier quoted context omitted.

> When you strlen() a UTF8 string, you don't get the length of the string, but instead the size in bytes. Yes, and? > What am I missing? A use-case? Where, in your C code, is it reasonable to get the number of multibyte characters instead of the number of bytes in the string? What are you going to use "number of unicode codepoints" for? Any usage that amounts to "I need the number of unicode codepoints in this string…

For example splitting, cutting and inserting strings into each other

> For example splitting, cutting and inserting strings into each other

That's not going to work without a glyph-aware library anyway; even if you are working with actual codepoint arrays, you can't simply insert a codepoint into that array and have a correct unicode string as the result.

Same for splitting.

Re: Some C habits I employ for the modern day

#95

Earlier quoted context omitted.

> So you use strlen() a lot and don't have to deal with multibyte characters anywhere in your code. It's not much of a strategy. You don't need to support all multibyte encodings (i.e. DBCS, UCS-2, UCS-4, UTF-16 or UTF-32) characters if you're able to normalise all input to UTF-8. I think, when you are building a system, restricting all (human language) input to be UTF-8 is a fair and reasonable design decision, and…

> I think, when you are building a system, restricting all (human language) input to be UTF-8 is a fair and reasonable design decision, and then you can use strlen to your hearts content. It makes no sense. If you only need the byte count then you can use strlen no matter what the encoding is. If you need any other kind of counting then you don't use strlen no matter what the encoding is (except in ASCII only environ…

> If you only need the byte count then even you can use strlen no matter what the encoding is.

No, strlen won't give you the byte count on UTF16 encodings.

> If you need character count then you don't use strlen no matter what the encoding is (except in ASCII only environment).

What use-case requires the character count without also requiring a unicode glyph library?

Re: Some C habits I employ for the modern day

#96

I'm a huge fan of the 'parse, don't validate' idiom, but it feels like a bit of a hurdle to use it in C - in order to really encapsulate and avoid errors, you'd need to use opaque pointers to hidden types, which requires the use of malloc (or an object pool per-type or some other scaffolding, that would get quite repetitive after a while, but I digress). You basically have to trade performance for correctness, wherea…

[deleted]

Re: Some C habits I employ for the modern day

#97
post #92

Earlier quoted context omitted.

> Internet is full of people asserting CVEs in C are only caused by not skilled enough devs. Sure, but those people are not here, and usually aren't on HN anyway. The internet is also full of people asserting that CVEs in C++ are only caused by not skilled enough devs, but I consider those people irrelevant too. The reasons for rejecting C++ in this forum have been repeated often enough that you should have seen them…

Yeah the same reasons as the flamewars on comp.lang.c and comp.lang.c++. WG21 could do a better job, but that least they acknowledge security has to be tackled somehow.

>> people choose almost anything over C++. The fact that "anything" also includes "C" is mostly incidental.

> Yeah the same reasons as the flamewars on comp.lang.c and comp.lang.c++.

I've never seen that reason in comp.lang.c and comp.lang.c++; I am skeptical that you have seen that reason.

Re: Some C habits I employ for the modern day

#98
post #16

I really dislike parsing not validating as general advice. IMO this is the true differentiator of type systems that most people should be familiar with instead of "dynamic vs static" or "strong vs weak". Adding complexity to your type system and to the representation of types within your code has a cost in terms of mental overhead. It's become trendy to have this mental model where the cost of "type safety" is paid i…

While I broadly agree with your general point, in that engineering is making a set of trade-offs, I don't necessarily agree that ditching type-safety in the example contexts you posted is the appropriate trade-off.[1] I'll ditch type-safety in experimental/exploratory code; I'll use Lisp (or, more recently, Python) to test if something is a good idea. For anything that ships to production, I think a basic level of ty…

I'm not talking about ditching type safety. I'm saying the whole concept of "safe" and "unsafe" as most people on HN understand it is flawed. The interesting part of a type system isn't whether the compiler checks types or if we just go lmao fuck it let's not even bother, it's whether or not you need to represent the types in your code in order for the compiler to check them. For the majority of what people want from type safety in a language like Javascript, the answer is that no, you don't need to, as long as you're willing to not have every single language feature under the sun.

With compiled languages you can statically infer a ton of type information without having to pepper your codebase with repeated references to what something is. Nominal typing essentially boils down to a double-check of your work, you specify the type separately and then purposely assign it to a variable, so that if you make a mistake with either part the compiler picks it up.

But those kinds of double-checks can be done for almost anything (outside of dynamic boundaries like io/dlls) without nominal type signatures in the code, as long as you jettison the ability to change types at runtime. No language as far as I can tell actually does this because we're all so obsessed with the false dichotomy of nominal and dynamic typing.

In JS everyone likes to use string unions in place of enums so let's use that as an example. If you have something that is only ever set as "foo" or "bar", that's effectively a boolean. If you receive that string in another function, make a typo and write if (str == "boo"), then in every single language I'm aware of that passes a compiler check. But it shouldn't, because the compiler has all the information it needs to statically catch that error and fail the build. The set of assignments to that variable and the set of equality checks on it provide the two parts of the double-check.

In a perfect world we'd have 10 of these "middle of the road" strongly typed static languages to choose from that all optimise for minimal type representation in their own unique way. But every time I see one of these projects pop up on HN it gets like 10 comments then disappears into the sunset because the programming community is so enraptured with the nominal type system of C and all the fucking bullshit Bjarne Stroustrup pasted on top of it 40 years ago. So we end up with this silly situation where the only things considered "safe" by the crowd are strict descendants of C/C++ with the array/pointer/string screw-ups that made those languages unsafe removed.

Re: Some C habits I employ for the modern day

#99

> I’ve long been employing the length+data string struct. If there was one thing I could go back and time to change about the C language, it would be removal of the null-terminated string. It's not necessary to go back in time. I proposed a way to do it in modern C - no existing code would break: https://www.digitalmars.com/articles/C-biggest-mistake.html It's simple, and easy to implement.

Even simpler, you can do something like this to have length-delimited AND null-terminated strings (written from memory, no guarantees of correctness etc.): char *lenstrdup(char *s) { int n = strlen(s); char *p = malloc(n + sizeof(int) + 1); if(p) { strcpy(p + sizeof(int), s); *(int*)p = n; p += sizeof(int); } return p; } void lenstrfree(char *s) { free(s-sizeof(int)); }

One of the advantages to the pointer + length approach is free substrings. This inline approach doesn't allow that.

Re: Some C habits I employ for the modern day

#100
post #73

Earlier quoted context omitted.

> So you use strlen() a lot and don't have to deal with multibyte characters anywhere in your code. It's not much of a strategy. You don't need to support all multibyte encodings (i.e. DBCS, UCS-2, UCS-4, UTF-16 or UTF-32) characters if you're able to normalise all input to UTF-8. I think, when you are building a system, restricting all (human language) input to be UTF-8 is a fair and reasonable design decision, and…

Am I missing something here? UTF8 has multibyte characters, they're just spread across multiple bytes. When you strlen() a UTF8 string, you don't get the length of the string, but instead the size in bytes. Same with indices. If you Index at [1] in a string with a flag emoji, you don't get a valid UTF8 code point, but instead some part of the flag emoji. This applies with any UTF8 code points larger than 1 byte, whic…

> When you strlen() a UTF8 string, you don't get the length of the string, but instead the size in bytes.

Exactly, and that's what you want/need anyway most of the time (most importantly when allocating space for the string or checking if it fits into a buffer).

If you want the number of "characters" (which can have two meanings: either a single UNICODE code point, or a grapheme cluster (e.g. a "visible character" that's composed from multiple UNICODE code points). For this stuff you need a proper UNICODE/grapheme-aware string processing library. But this is needed only rarely in most application types which just pass strings around or occasionally need to split/parse/tokenize by 7-bit ASCII delimiters.

Post reply on HN