11 ms·
C never has just one way to do something. myArr[5] == 5[myArr] == (insert pointer arithmetic that I won't write here without a compiler check). I think that par
by 6D794163636F756 3y ago
C never has just one way to do something. myArr[5] == 5[myArr] == (insert pointer arithmetic that I won't write here without a compiler check). I think that part of C's beauty is that it gives you freedom. Freedom to shoot yourself in the foot, freedom to write hyper efficient code, and freedom to choose another tool.
I agree that this will never be implemented as a standard, but I think that's a good thing. Higher level languages push against their boundaries non stop. Java has libraries and frameworks that fundamentally change the syntax and functionality of the language. C knows what it is. If you want something that it can't do it promises that you can either build it yourself or switch to a different tool.
All of this to say, C has a single suggested way of doing this: using a different language. That's part of why we built them
- adastra22 3y agoThose are syntactic sugar for the same thing though. Array[5] is just shorthand for *(Array + 5), which is why 5[Array] also works (because addition is commutative). Note that C does have strong conventions, such as that strings are terminated by a zero byte. Nothing in the language demands that, it’s just a convention! C could adopt better conventions.
- astrobe_ 3y ago> Note that C does have strong conventions, such as that strings are terminated by a zero byte Stated the same on HN earlier, but someone pointed out that literal strings are ASCIIZ.
- adastra22 3y agoOne common trick in safer C libraries is to encode the length of the string one word prior to the beginning of the string. So "hello world" in memory would be 11 'h' 'e' 'l' 'l' 'o' ' ' 'w' 'o' 'r' 'l' 'd' '\0' ptr ^ C could be upgraded to do this in future versions, without too much backwards incompatibility.
- JohnFen 3y ago> C could be upgraded to do this in future versions, without too much backwards incompatibility. But I'd hope that doing that would always be optional. There are numerous situations where that would seriously get in the way.
- ranger_danger 3y agoCould you mention one of them?
- JohnFen 3y agoSure. For instance, there are times when you need to pack strings tightly together. Adding an extra byte or two before the start of the string would get in the way. You could work around it in many cases, but it makes the code uglier and harder to understand/maintain. One of the things that makes C particularly suitable for certain sorts of tasks is that it's mostly WYSIWYG when it comes to the relationship between data structures and the actual memory layout. Having "hidden" things like a length value before the string steps on that.
- teo_zero 3y agoI agree on the first paragraph, but the second one applies poorly to strings: char *s = "hello"; "hello" has length 6 because there's a hidden \0 even if I never wrote it in the code.
- ranger_danger 3y agoif you wanted to pack strings together tightly, couldn't your string library have a separate "array" concept where all the sizes are stored separately?
- eesmith 3y agoStrings can point anywhere in the malloc'ed region: char buffer[] = "railroad"; char *s = buffer; char *t = buffer + 4; printf("mult: %ld\n", strlen(s) * strlen(t)); Suppose I read 100 bytes, formatted as "{name}\t{rank}\t{serial number}\t" using variable length parts. I can read the data into a single string buffer, replace the commas with NULs, and set up strings pointing to the middle of the buffer; typedef struct {char buf[101], char *name, char *rank, char *serialno} person; /* 100 bytes formatted as: name\trank\tserial no\t. */ int read_data(FILE *f, person *p) { char *s; if (fread(p->buf, 1, 100, f) != 100) return -1; p->buf[100] = 0; p->name = p->buf; if ((s = strchr(p->buf, '\t') == NULL) return -2; *s = 0; p->rank = s+1; if ((s = strchr(s+1, '\t') == NULL)) return -2; *s = 0; p->serialno = s+1; if ((s = strchr(s+1, '\t') == NULL)) return -2; *s = 0; return 0; } person subject; if (read_data(stdin, &subject)) fail("cannot read."); print("Hello %s %s.\n", subject.rank, subject.name); ... Even better, the protocol might have NUL characters already in the code, expecting C strings to point to the correct start.
- Someone 3y ago> literal strings are ASCIIZ. If only. In C, it’s a (95+5)-item character set that happens to be a subset of ascii. See https://en.cppreference.com/w/c/language/charset https://en.cppreference.com/w/c/language/charset: “The basic literal character set consists of all characters of the basic character set, plus the following control characters” That page also explicitly says: The following characters are not in basic execution character set, but they are required to be encoded as a single byte in an ordinary character constant or ordinary string literal. Code unit Character Glyph U+0024 Dollar Sign $ U+0040 Commercial At @ U+0060 Grave Accent `”* If I read that correctly, if you write a ‘$’ in a string literal before C23, there’s no guarantee that if gives you a byte with value 0x24. Of course, C++ is different. Like C, it makes a distinction between the encoding of source files (nowadays called the “basic character set”) and the encoding that the compiler converts literals to (nowadays called the “basic literal character set”), but it seems to put even fewer restrictions on them (in my cursory reading) Also (https://en.cppreference.com/w/cpp/language/charset https://en.cppreference.com/w/cpp/language/charset): “Mapping from source file (other than a UTF-8 source file) (since C++23) characters to the basic character set (until C++23) translation character set (since C++23) during translation phase 1 is implementation-defined, so an implementation is required to document how the basic source characters are represented in source files.”* If I understand that correctly, you can’t portably write an euro sign in C++ source files in C++ foe C++23 Also, chances are this changed in subtle ways between C and C++ versions.
- deleted 3y ago[deleted]
- thelopa 3y agoMany of the str functions in the C standard library assume a nul terminator.
- adastra22 3y agoYes, but aside from string literals pointed out by a sibling comment, nothing in the language itself dictates this convention. The C library could be augmented with functions which expect strings structured in other ways.
- ixtenu 3y ago> nothing in the language itself dictates this convention. String literals are nul-terminated, e.g.: "foo"[3] == '\0'
- tedunangst 3y agoMy copy of the C standard says "A string is a contiguous sequence of characters terminated by and including the first null character."
- shrimp_emoji 3y agoChecked arithmetic has been implemented in the standard with `ckdint.h`, so give it 50 more years!