[HN Gopher] C uses "&" for the address-operator because 'ampersa...
___________________________________________________________________
C uses "&" for the address-operator because 'ampersand sounds like
"address"'
Author : pkapka
Score : 183 points
Date : 2023-10-10 09:37 UTC (13 hours ago)
(HTM) web link (softwareengineering.stackexchange.com)
(TXT) w3m dump (softwareengineering.stackexchange.com)
| nailer wrote:
| This is right up there with "ng stands for angular".
|
| No it doesn't.
| latexr wrote:
| The correct link is
| https://softwareengineering.stackexchange.com/a/273268/94821,
| which points directly to the answer.
| floodle wrote:
| Thanks! I was confused by this
| snshn wrote:
| Funnily, that's how I made myself remember that. Without knowing
| about Ken's idea.
| [deleted]
| csours wrote:
| How do you keep your sanity while using pointers in C?
| ordu wrote:
| Don't use pointers to functions, or if you must then hide them
| behind typedefs.
| zabzonk wrote:
| i've taught c and c++ extensively commercially, and i really
| can't remember anyone having real problems with understanding
| pointers, despite some trepidations they might have had when
| the topic was first introduced.
| csours wrote:
| I understand pointer operations just fine. It's very hard for
| me to keep up with what is happening line to line.
|
| So, do people use consistent naming standards? Comment every
| line? Look at the assembly language produced by the compiler?
| zabzonk wrote:
| i'm not sure i understand your problem - why do you find
| understanding a basically sequential program so hard?
| csours wrote:
| Thank you for your constructive feedback.
| zabzonk wrote:
| it's not feedback, it's a question regarding your
| comments.
| ranger207 wrote:
| Valgrind
| johnklos wrote:
| Amperdress.
| aspenmayer wrote:
| Maybe it's just me, but ampersand sounds nothing at all like
| address to my English-speaking American ear. Am I missing
| something?
| tragomaskhalos wrote:
| Thought that as well, but try to imagine someone bellowing the
| word over the incessant clacking of teletypes and it _almost_
| works ...
| Tommstein wrote:
| It's not just you.
| bogwog wrote:
| Same! Someone should post a video/audio recording of the
| pronunciation. Even trying to imitate different accents I'm
| familiar with, I can't find one where the two words sound even
| remotely similar lol
| pavlov wrote:
| Next they're going to tell us that "asterisk" sounds like
| "dereference".
|
| That's just how they talked in 1972 in New Jersey where Bell
| Labs is located.
| rpz wrote:
| * star start start of
|
| ;)
| pezo1919 wrote:
| LOL!
| aspenmayer wrote:
| My stepdad is from NJ and pronounces toilet as tore-let. He's
| a real character and now I don't know if you're serious or
| not and it's hilarious to me as a non-NJ person who has
| visited and met his side of the family.
| paulddraper wrote:
| We obviously can't take anyone seriously who says "wudder".
| fanf2 wrote:
| I guess the similarity is between and & addr.
| ilyt wrote:
| The fact C was made on crack
|
| It's where the C comes from!
| Cthulhu_ wrote:
| These characters are from its predecessor, B, though.
|
| Funnily enough, the guy that made B is also behind Go, where
| * and & are still a thing.
| Izkata wrote:
| Well, maybe B is B because it was the Beta version of C
| kunley wrote:
| Unlikely, but maybe your comment was.
| paulddraper wrote:
| Depends.
|
| Ampersand begins with ae.
|
| Address can use ae or the reduced vowel @.
|
| AH-dress vs eh-DRESS
| lol768 wrote:
| An equally confused BrE speaker reporting in! Can confirm it's
| not just AmE.
| Ylpertnodi wrote:
| I've never seen BrE and AmE used so like this - fantastic!
| Apart from on mobile...bre and ame they will become.
| Hopefully context will explain.
| r87 wrote:
| Odin uses ^ because pointers are pointy.
| paulddraper wrote:
| Asterisks are kinda pointy.
| elurg wrote:
| Also Pascal.
|
| And C++/CLI uses ^ for "managed pointers" (pointer to .net
| objects) and % for "managed references" which means there are
| all-together 4 ways to declare various types of pointers which
| is super-fun.
| IAmYourDensity wrote:
| I have a pet theory that '#' and '*' have such prominent roles in
| C because Thompson and Richie developed B at Bell Labs in 1969
| when the first push button phones were appearing with '#' and '*'
| buttons.
| codesnik wrote:
| TIL "ampersand" etymology. from the Oxford dictionary: "Origin:
| late 18th century: alteration of and per se and '& by itself is
| and ', formerly chanted as an aid to learning the sign."
| twoodfin wrote:
| See also:
|
| https://news.ycombinator.com/item?id=32249465
| zabzonk wrote:
| and of course in c++ it's also the reference declarator.
| [deleted]
| robertlagrant wrote:
| Hot take: @ might've been a good alternative.
| tsegers wrote:
| I'd argue @ is more suitable for a dereference operation than
| an "address of" one. It functions that way in an email address
| too.
| bsza wrote:
| Also, then "int @p" would read "integer at p" which is
| exactly what "int *p" means.
| frou_dh wrote:
| That's precisely what Clojure did, where @foo is syntactic
| sugar for (deref foo)
| amelius wrote:
| So address-of could be an "@" symbol, but upside down.
| anticensor wrote:
| Or a spanish question mark ?.
| robertlagrant wrote:
| Ah yes - that's true.
| jandrese wrote:
| I agree, big missed opportunity in C's development.
| pjmlp wrote:
| Which is what Pascal dialects use.
| jjgreen wrote:
| Instance-variable heavy Ruby code does look rather like someone
| has sneezed on the monitor, so I think it would have been a bad
| move, aesthetically ...
| user3939382 wrote:
| Nethack or code? You decide
| JoeAltmaier wrote:
| Yup. But as I understand it @ wasn't available on the terminals
| used to create C. Likewise #. They were used for later
| features, once they could actually be typed. Happy outcome,
| that there were characters available for fresh features, since
| C used absolutely everything available on the original (ADM?)
| terminals.
|
| Another curious thing: Unix came shortly after and was entirely
| typed with lower case. Because those same terminals had only
| one font (font ROMs were tiny back then, and expensive). It
| looked like UPPERCASE but in fact the keyboard produced
| lowercase. Once better terminals were used to edit the code it
| was noticed for the first time(?) that it's all be edited as
| lowercase.
|
| Or so the story went, back in those days, when it was all new.
| aidenn0 wrote:
| As far as I know @ on modern keyboards above the two from the
| IBM Selectric[1], released in 1961; the Model D and the VT-52
| both copied the keyboard layout. The 1963 ASCII draft had @,
| despite not having lowercase yet.
|
| Prior to IBM, it was on at least the Underwood
| typewriters[2], so it was never quite absent.
|
| 1: https://en.wikipedia.org/wiki/IBM_Selectric#/media/File:IB
| M_... Note that the number-row is only different from modern
| keyboards with the cent-sign being replaced with a caret (the
| cent-sign was never included in ASCII)
|
| 2: https://upload.wikimedia.org/wikipedia/commons/a/a4/Ernest
| _H...
| kps wrote:
| 1963 ASCII was upper-case only, and many early terminals
| (notably for Unix, including the Teletype 33) were upper case
| only. `stty lcase`, which maps upper-case input to lower
| case, existed early -- https://www.tuhs.org/cgi-
| bin/utree.pl?file=V1/man/man2/stty....
| trealira wrote:
| That corroborates what I've read.
|
| The DEC PDP-11 assembler used the @ symbol for dereferences
| of registers ("@Rn" or "(Rn)" dereferenced a register, for
| example).
|
| However, in Unix, the terminal convention was to use the @
| symbol to delete the current line, and they didn't have a DEC
| assembler yet, so they used the asterisk (*) instead in B, as
| well as in the Unix PDP-11 assembler, which was written in B.
|
| I'm paraphrasing this Quora post (which lists primary and
| secondary sources): https://www.quora.com/Why-did-the-
| developers-of-C-decide-to-...
| marssaxman wrote:
| Some dialects of BASIC used @ as a shortcut for the `VarPtr`
| operation.
| elurg wrote:
| Pascal uses this syntax.
|
| Also "pointer to integer" is written as "^integer" which is
| better than "int _".
|
| Syntax also doesn't allow confusing stuff like like "int a,
| _b;".
| brandmeyer wrote:
| > "^integer" which is better than "int"
|
| I agree that it reads a little better. But as a small-handed
| person, it is unfortunately much more uncomfortable to type.
| sureglymop wrote:
| Honestly that fully depends on your locale and keyboard
| layout. So it really shouldn't influence programming
| language syntax design.
| bmacho wrote:
| My computer has buttons, and characters printed on it. So
| I can't really change the distance between characters.
| mock-possum wrote:
| My immediate thought as well.
|
| Where's that value in memory? It's @ the address.
| Dobbs wrote:
| I didn't think @ took on the "at" meaning until email came
| around.
| eesmith wrote:
| RFC 20 shows "@" defined as "commercial at" in 1969.
| https://www.rfc-editor.org/rfc/rfc20.html . That was two
| years before Tomlinson used it for email addressing.
|
| EDIT: "Creation of Computer Input in an Expanded Character
| Set" at https://ejournals.bc.edu/index.php/ital/article/downl
| oad/292... from 1968, p112, describes it simply as "at".
|
| EDIT #2: "TRANSLATION FROM MONOTYPE TAPE TO GRADE 2 BRAILLE"
| at p83 of https://archive.org/details/researchbulletin05lesl/
| page/82/m... from 1964 describes that symbol as the '"at"
| sign'.
|
| I think that is early enough to say that email did not
| influence the "at" meaning but rather the other way around.
| tsimionescu wrote:
| What do you think it meant before that?
| narag wrote:
| Arroba:
|
| https://en.wikipedia.org/wiki/Arroba
| [deleted]
| syockit wrote:
| As for me, I was taught it meant "alias", used when
| introducing nickname together with real name.
| aidenn0 wrote:
| There are claims it comes from the latin "ad" similar to how
| & comes from the latin "et" but the etymology is far less
| certain, with the french a being another possible source.
|
| What I can't find is when it was first used in the US for
| indicating home-team for sports. E.g. [1] where there is vs.
| or @ depending on whether it is a home or away game. I
| suspect it's relatively modern, but not sure how far back it
| goes.
|
| 1: https://www.mlb.com/redsox/schedule/2023-09
| johannes1234321 wrote:
| The oldest trace of @ being used to mean "at" can be traced
| to typeriters for commerce around 1880, where it was used as
| "5 apples @ 10 p" meaning "5 apples at 10 pence each."
|
| At least that's what German Wikipedia Claims while the
| corresponding paragraph in english Wikipedia is short.
|
| https://de.wikipedia.org/wiki/At-Zeichen
|
| https://en.wikipedia.org/wiki/At_sign
| gattilorenz wrote:
| More recently (but still 1968, before email): "In ALGOL 68,
| the @ symbol is brief form of the _at_ keyword; it is used
| to change the lower bound of an array. For example:
| arrayx[@88] refers to an array starting at index 88. "
| d-lisp wrote:
| French wikipedia traces the usage of @ to signify "a" (at)
| back to Renaissance !
| jfk13 wrote:
| The formal name of the Unicode character U+0040 '@' is, in
| fact, COMMERCIAL AT.
|
| https://en.wikipedia.org/wiki/At_sign#Unicode
| Sanzig wrote:
| It's also the "a commercial" in Quebec French [1].
| Despite lacking the accent on the A (a), the intention of
| the A is to stand in for the single letter French word
| "a" (at) [2].
|
| [1] https://vitrinelinguistique.oqlf.gouv.qc.ca/fiche-
| gdt/fiche/... [2] https://www.noslangues-
| ourlanguages.gc.ca/fr/cles-de-la-reda...
| ape4 wrote:
| Its impossible for my brain to imagine anything else now
| adrian_b wrote:
| Some people in that discussion wonder about "->", which is used
| for indirect addressing through a structure member.
|
| When C has added structures, which did not exist in B, it has
| taken the keyword "struct" and also both "." and "->" from the
| IBM PL/I language, from which C has also taken some other
| features.
|
| In general, almost any feature added by C to B was taken either
| from PL/I or from Algol 68. The exceptions are "continue" and the
| generalized "for", which did not exist in any previous language.
|
| (However the generalized "for" of C was a mistake, because it
| complicates the frequent use cases in order to simplify seldom
| encountered use cases. The right way to generalize "for", i.e.
| with iterators, was introduced by Alphard in the same year with
| C, i.e. in 1974.) (Compare "for (I=0;I<N;I+=5) {" of C with "for
| I from 0 to N by 5 do" or "for I in 0:N:5 do" of previous
| languages. C requires typing a lot of redundant characters in the
| most frequent cases.)
|
| The oldest symbol for indirection through a pointer (in the
| language Euler, in January 1966) was a raised middle dot (i.e. a
| point). This was before ASCII and ASCII did not include the
| raised middle dot (U+00B7), so it was replaced by the most
| similar ASCII character, "*".
|
| Euler had used "@" for "address of" and indirection was a postfix
| operator, as it should. Making "*" a prefix operator in B and C
| was a mistake, which forced the importing of "->" from PL/I, to
| avoid an excessive number of parentheses. Otherwise "(*x).y"
| would have been needed, instead of "x->y". With a postfix "*",
| that would have been "x*.y", and "->", would not have been
| needed.
|
| In CPL, the ancestor of BCPL and B, indirection was implicit,
| like with the C++ references. Instead of having an "address of"
| operator, CPL had a distinct symbol for an assignment variant
| that assigns the address of a variable, instead of assigning its
| value.
| lowbloodsugar wrote:
| >because it complicates the frequent use cases in order to
| simplify seldom encountered use cases.
|
| Putting complex logic in the three places of a for loop is
| something we all frown on now because of readability and bugs,
| but back then it was almost more common than just iterating
| from 1 to N. Same for dropping through case statements -
| frowned on now (rightly) because gotcha bugs, but used heavily.
|
| >Making "*" a prefix operator in B and C was a mistake
|
| C dominates for the same reason it is terrible: it gets shit
| done for some value of "shit". In this light, there are no
| mistakes. There are other languages that don't make these
| "mistakes" and, behold, nobody wrote the majority of the
| world's operating systems and software in them. I've used C
| when the viable options were hand-crafted assembly or C. There
| are no mistakes here, only practicalities.
| AnimalMuppet wrote:
| > Compare "for (I=0;I<N;I+=5) {" of C with "for I from 0 to N
| by 5 do" or "for I in 0:N:5 do" of previous languages. C
| requires typing a lot of redundant characters in the most
| frequent cases.
|
| Um, "for (I=0;I<N;I+=5) {" is _fewer_ characters than "for I
| from 0 to N by 5 do".
| f1shy wrote:
| I do not remember the author of the quote: A program is
| written once and read multiple times. Optimize for reading,
| not writing.
|
| The argument "is more keystrokes" in this context is beyound
| what i can comprehend.
| Vvector wrote:
| The most frequent case would be increment by 1, so:
|
| for (I=0;I<N;I+=1)
|
| versus
|
| for I from 0 to N do
| adrian_b wrote:
| "for I from 0 to N by 5 do" is the verbose variant, which is
| typical for a language like PL/I or Algol 68.
|
| The syntactically equivalent, but non-verbose, is "for I [?]
| 0:N:5 <", which beats easily C.
| jandrese wrote:
| Do people have normally keyboards with a [?] key?
| loup-vaillant wrote:
| Just remove the [?] and < characters, and make braces
| mandatory: for i 0:N:5 { // loop
| body }
|
| By the way, the same should have been done with if and
| while: optional parentheses, mandatory braces:
| if a == b { // code } while idx
| < end { // code }
| d-lisp wrote:
| It's possible that parsing a complex condition wrapped by
| parentheses was found more convenient.
| AnimalMuppet wrote:
| Sure. And the observant will note that I didn't say that C
| was shorter than that version. Even if you replace "[?]"
| with "in", it's still shorter.
|
| Still... when did that syntax come out? Was it in Algol 68,
| or PL/I? It seems a bit unfair to complain about C being
| verbose if it was shorter than anything else available at
| the time.
| adrian_b wrote:
| "[?]" was actually proposed for Alphard, at the same time
| with C.
|
| When later implemented, including in an Algol 68 variant
| that inspired the UNIX Bourne shell, "[?]" was replaced
| with "in", which could be written with ASCII.
|
| Algol 68 could use either keyword pairs, like "do" and
| "od" (which became "do" and "done" in the UNIX Bourne
| shell) or, optionally, various kinds of parentheses in
| their place, for conciseness.
|
| The notation "0:N:5" or "0:N", when the step is 1, for
| arithmetic progressions is ancient. Even Fortran used it,
| but with the mistake of using comma instead of colon,
| which introduced a syntactic ambiguity, because comma was
| also used for other purposes. Using colon started with
| Algol 60, but that one preferred keywords instead of
| symbols in the arithmetic progressions used inside "for",
| so it did not use the notation consistently.
|
| Fortran in 1954 or the language of Heinz Rutishauser, in
| 1951 (the first one with a "for" statement), were already
| much more concise than C.
| alexeiz wrote:
| > The right way to generalize "for", i.e. with iterators, was
| introduced by Alphard in the same year with C, i.e. in 1974.)
| (Compare "for (I=0;I<N;I+=5) {" of C with "for I from 0 to N by
| 5 do" or "for I in 0:N:5 do" of previous languages.
|
| Really? How do you do the C's equivalent of `for(i = 0; i < N
| && j < M; i++, j++)` with your `for I from 0 to N` syntax? The
| for loop in C is extremely flexible and it captures the idea of
| the loop perfectly: there is the initialization block, the exit
| condition and the iteration. In other languages at that time
| the for loop was written in terms of a range, but without a
| strong range abstraction such loop is really primitive and
| limited in applicability.
| nyssos wrote:
| > In other languages at that time the for loop was written in
| terms of a range, but without a strong range abstraction such
| loop is really primitive and limited in applicability.
|
| That's a good thing: it gives you a clear syntactic marker
| for "this loop definitely terminates". There's already a full
| power anything-goes looping construct: `while`.
| professoretc wrote:
| But `while` doesn't restrict the scope of the variable(s)
| to just the loop. I believe there was a proposal to add
| while(int i = 0; i < 100) { ... }
|
| as a valid syntax to C++ (which would restrict the scope of
| i to the loop), as you can already do
| if(int i = f(); i > 0) { ... }
|
| but it didn't go anywhere.
| a_e_k wrote:
| I'd just use a for with an empty update clause for that:
| for (int i = 0; i < 100; ) { ... }
| justincredible wrote:
| [dead]
| adrian_b wrote:
| Your example would be "for i in o:N for j in o:M do".
|
| Equivalent syntax was used in Fortran for writing cycles in a
| simpler way than in C already 20 years before C. ("do 10
| i=0,N do 20 j=0,M")
|
| The only case when the C "for" is useful is when the third
| operation is neither an addition nor a subtraction. The most
| frequent such case is when the operation is a link
| dereferencing, for accessing a linked list.
|
| Such cases, for visiting all members of some non-array
| aggregate data, e.g. linked lists or trees, are solved more
| clearly with iterators.
| MrJohz wrote:
| I interpreted that line to be two separate clauses: firstly,
| a note that the statement that the correct generalisation for
| for loops is iterators, which were introduced in Alphard;
| secondly, an unrelated point about how the C-style
| generalised for loop is more verbose for the simple case than
| existing syntaxes.
|
| That is, the commenter was not asserting the supremacy of
| "from 0 to N" as a for-loop construct, but rather asserting
| the supremacy of iterators, and pointing out how poor the
| C-style syntax is even compared to its less-generalised
| cousins.
| adrian_b wrote:
| Before C and Alphard, all the "for" loops had control
| variables that took all values of some arithmetic
| progression.
|
| Even today, such simple loops with arithmetic progressions
| include an overwhelming majority of all "for" loops.
|
| The C syntax made writing these simple "for" loops more
| difficult, by having to write a lot of redundant symbols,
| instead of writing the minimum number of separators. Also
| for reading, the redundant symbols obscure the meaningful
| text.
|
| The C syntax allows the writing of "for" loops where the
| values of the control variables are not taken from a
| progression, but they are for instance the values of the
| links of a linked list.
|
| This kind of "for" loops can be written in a simple way by
| using iterators, without complicating the syntax of the
| loops with simple arithmetic progressions.
|
| In modern C++ there is no longer any case when you would
| want to use the C kind of "for", but the kinds of loops
| used by languages like C++ already existed in languages
| introduced at about the same time with C, e.g. Alphard and
| Clu.
| a_e_k wrote:
| Another good real-world one that I've done is something like:
| for (bit = 1; bit <= 128; bit <<= 1)
|
| Personally, I like the flexibility.
| adrian_b wrote:
| A better syntax for loops with geometric progressions like
| this would be obtained by modifying the syntax for writing
| arithmetic progressions (e.g. "a:b:c") by using a different
| separator symbol.
|
| For example, if the separator for geometric progressions
| would be ":>", your loop example would become "for bit in
| 1:>128:>2". Another example of (non-ASCII) separator would
| be "for bit in 1[?]128[?]2"
| kazinator wrote:
| Such syntax benefits from a comprehensive target language
| to compile into, in terms of which it can be understood,
| if necessary.
| bxparks wrote:
| Heh, hopefully not too often. First I thought this loops
| 128 times. Then 7 times. Then 8 times. Then I thought
| "undefined behavior" if bit is a uint8_t. But then I
| thought, I don't have freaking clue because I can't keep
| all of C's implicit casting and arithmetic operation rules
| in my head.
| ordu wrote:
| for-loop in C is still primitive and limited in
| applicability, while it makes the most frequent use-case much
| more difficult.
|
| For example, it is normal practice to do some of
| initialization outside of a loop. It is normal to deal with
| finishing loop by using goto or if-branching after the loop
| (think of a search, that can be succesful or not). It is
| normal to ignore update counter part of loop and do updates
| in a body of the loop, because either updates are too big to
| squeese them between into for, or you need to do something
| between updating your counter and checking for the necessity
| of running another iteration.
|
| With all this said I know 2 another approaches to the
| problem.
|
| 1. Common Lisp approach: create really flexible loop clause,
| allowing to represent any loop in a structural way. I'd
| recommend to look at cl-iterate package for CL, to see what
| happens to maniacs who had chosen this way.
|
| 2. A less ambitious approach defining some simple loops for
| most frequent cases (while, range iteration, iteration by
| iterator) and a loop for a general case looking like "loop {
| _iteration_ } ".
|
| I personally prefer the second approach. I loved C-way, then
| I was a big fun of a Lisp-way, but now I believe that it is
| silly to create a whole new language just to write iteration,
| and a half-baked attempt to cover with for-loop more cases
| then just range iteration has more downsides than upsides.
| kazinator wrote:
| Using the for(;;) loop in Awk, and the C preprocessor, in a
| project called cppawk, I created a loop facility that has
| multiple clauses of different types, that can combine in
| parallel or as Cartesian-product, and are programmer-
| definable.
|
| https://www.kylheku.com/cgit/cppawk/tree/cppawk-iter.1
|
| The above manual page includes an example of how to define an
| _alpha_range_ clause that iterates over string ranges like
| alpha_range(var, "000", "999") or alpha_range(var, "AAA",
| "ZZZ").
|
| There is a conditional clause if(...) which takes a condition
| and another clause as arguments. The iteration of the other
| clause is suspended while the condition is false.
|
| At the shell prompt: add the values of the odd integers in
| the range 1 to 50. $ cppawk ' >
| #include <iter.h> > > BEGIN { > loop
| (range (i, 1, 50), > if (i % 2 == 1, summing
| (sum, i))) > ; > print sum > }
| > ' 625
|
| Though _if_ is an Awk keyword, this isn 't a problem because
| if is a clause, not an ordinary expression. Moreover, though
| the clause is defined by macros, none of them are called _if_
| ; they have _if_ embedded in their name.
| f1shy wrote:
| What you are doing there is no for. Not in the mathematical
| sense of "for all values in a set". The semantic of the word
| "for" should matter. If you want to iterate 2 variables i and
| j is much better to do it explicitly. It will be much more
| readable.
| tralarpa wrote:
| > the generalized "for" of C was a mistake, because it
| complicates the frequent use cases in order to simplify seldom
| encountered use cases
|
| The worst offender is the quasi-obligatory "break" statement in
| "case" blocks. Fall-through cases are useful for things like
| lexers but probably not needed in 99.999% of other programs. I
| wonder how many millions of (wo)man hours have been wasted on
| debugging missing breaks. (yes, I know that linters exist)
| WalterBright wrote:
| In D, if there are no intervening statements:
| case 1: case 2: ... code ...
|
| the fallthrough is allowed. case 1:
| ... code ... case 2: ... code ...
|
| Is an error. But `goto case` can be used:
| case 1: ... code ... goto case;
| case 2: ... code ...
|
| which makes it clear. No new keywords are needed. C could
| adopt this easily. All those /* fallthrough */ comments and
| warnings and compiler switches will just go away.
|
| Oh, and obviously: case 1: ...
| code ... goto default; default:
| ... code ...
|
| also works!
| pjmlp wrote:
| Incidently lint was invented exactly because of improving the
| way C was, they decided it was better in the UNIX tradition
| to add yet another tool, which those millions rather not use.
| lisper wrote:
| > The worst offender is the quasi-obligatory "break"
| statement in "case" blocks.
|
| This was (almost certainly) done to simplify the compiler.
| CASE in C is not actually a structured control construct
| despite its syntactic appearance, it's just a computed GOTO.
| This is what makes things like Duff's device [1] possible.
|
| [1] https://en.wikipedia.org/wiki/Duff%27s_device
| itsphilos wrote:
| I didn't know about Duff's device, which looks pretty
| interesting! Thanks for sharing
| lisper wrote:
| Sure, but just for the record IMHO duffs device is an
| abomination and an illustration of how badly broken C is.
| No one should ever actually use it.
| nuancebydefault wrote:
| What I find inconvenient is that a case body can be made
| with or without curly brackets. I'd rather have they were
| mandatory, like when an if statement aplies to more than
| one statement. The downside is that you need more
| indentation to have a logical curly brackets structure.
|
| Choices/options for the same result, tend to make code less
| readable.
| codr7 wrote:
| Yeah, I remember having my mind blown when I first
| discovered Duff's Device.
|
| My mental picture of what C-compilers are up to turned out
| to be a lot more sophisticated than reality.
|
| But having written a few Forth-interpreters, it makes total
| sense to me. Treating the input as a mostly unstructured
| stream of tokens is very convenient.
| bxparks wrote:
| I think computed-GOTO is easier to understand and more
| flexible than Duff's device, but computed-GOTO is not part
| of the C standard. It is sometimes available as a non-
| portable extension, e.g.
| https://gcc.gnu.org/onlinedocs/gcc/Labels-as-Values.html.
| Anyone know why it is not included in C?
| lisper wrote:
| Computed go to was not quite an accurate description. I
| probably should have said "dispatch table" instead.
| flohofwoe wrote:
| No separate linters needed, but details differ between
| compilers.
|
| GCC has a warning in the '-Wextra' warning set, Clang
| requires the explicit option `-Wimplicit-fallthrough', MSVC
| is completely silent (apparently it's in the CppCoreCheck
| rules though).
|
| This should really be in the default warning set with an
| annotation that the fallthrough is intended (unless the case-
| branch is completely empty).
| reactordev wrote:
| break; has a special color value in my IDE's. Just so it's
| loud. Strictly because of what you describe.
| AnimalMuppet wrote:
| That's not a bad idea, but it still leaves you having to
| notice when the loudness is silently missing. (It's
| _easier_ when it 's loud, but still...)
| bluecalm wrote:
| You don't really need a linter. It's just a warning setting,
| see: -Wimplicit-fallthrough
|
| From the compiler docs. It's just not a problem. If you waste
| time once and learn about warning options in the compiler you
| will be better off anyway. It's like with assignment being an
| expression panic - something that maybe bites you once and
| then you learn to read the compiler warnings and it never
| causes problems again. If you don't want to read then there
| is: -Werror
|
| Available.
| kps wrote:
| That (also) came from BCPL. (BCPL had a separate `endcase`
| statement; `break` applied only to loops. It also had `docase
| <expr>`, which is the equivalent of a loop `continue`, re-
| entering the `switchon`.)
| vincent-manis wrote:
| As I recall, B was modelled on an early BCPL compiler that
| didn't have an ENDCASE statement, hence the overloading of
| break for exiting a switch block.
| [deleted]
| cassepipe wrote:
| Note that gcc and clang will warn you about fallthrough
| statements i you use -Wextra and that you have to either have
| insert a / _fallthrough_ / comment to make your intent clear.
|
| Pity the (wo)man who does not use -Wall -Wextra for (s)he is
| truly mistaken
| a_e_k wrote:
| C++17 now has standardized the [[fallthrough]] attribute:
|
| https://en.cppreference.com/w/cpp/language/attributes/fallt
| h...
|
| (For backwards compatibility, it still must fallthrough
| with or without the attribute; the attribute just signals
| programmer intention and silences the warning.)
| flohofwoe wrote:
| Clang actually doesn't warn in -Wextra:
|
| https://www.godbolt.org/z/99ejvY9Pc
|
| It requires the separate option -Wimplicit-fallthrough:
|
| https://www.godbolt.org/z/GP576zG9h
|
| (which tbh sounds like a bug, because usually Clang tries
| to emulate GCC behaviour)
| fanf2 wrote:
| The prefix * in C comes from prefix ! in BCPL. C's weird a[b]
| == b[a] is also a hidden BCPLism.
|
| BCPL has infix ! as well as prefix ! so you write an array
| index expression like array!index instead of array[index].
| Infix ! is commutative like addition and [] in C.
|
| You declare structures in BCPL by defining a constant for the
| offset of each member, so you can write object!MEMBER somewhat
| like C object->member. The semantics of -> in early C were very
| similar to BCPL infix ! except that members had types as well
| as offsets, but like BCPL there was nothing to tie a particular
| member to a particular structure as there is in modern C.
|
| There's a certain elegance to BCPL's syntax that you don't get
| from prefix-only or postfix-only indirection operators. C might
| have been better if it had stuck closer to BCPL in this
| respect, but sadly * conflicts with infix multiplication.
|
| Some readers might also have used BCPL-style syntax for WIMP
| programming in BBC BASIC on RISC OS.
| masklinn wrote:
| > Otherwise "(*x).y" would have been needed, instead of "x->y".
| With a postfix "*", that would have been "x*.y", and "->",
| would not have been needed.
|
| I mean technically the compiler could just have been less
| stupid and made `.` auto-deref, it's not like C has operator
| overloading so the LHS is either a struct or a pointer, not
| both.
| hknapp wrote:
| https://stackoverflow.com/questions/13366083/why-does-the-
| ar...
| atilaneves wrote:
| Proof of the fact that this works is that D does exactly
| this.
| bluecalm wrote:
| There is something to "explicit is better than implicit"
| mantra. I appreciate the C way because if I write a.b and
| it's an error it clarifies what's going on in my head (I now
| know a is a pointer not an object).
| masklinn wrote:
| > There is something to "explicit is better than implicit"
| mantra.
|
| I'll entertain this when C fixes (or at least removes)
| integer promotion, which is a source of far more bugs and
| misunderstandings than this could ever be: `.` auto-deref-
| ing does not actively undermine what little type system C
| has.
| sigsev_251 wrote:
| Integer promotion will probably never be removed from the
| fundamental types (char, signed char, short, etc.). You
| can use `_BitInt`(N) types in the future which don't
| follow the implicit integer promotion rule. There are at
| least two compilers today that implement it (clang and
| SDCC).
| bluecalm wrote:
| Man, this is completely unrelated problem. Implicit
| operator overload is just a bad design. Integer promotion
| has advantages and disadvantages, especially in a
| language like C where you often use 8bit or 16bit types
| for memory optimization/alignment reasons.
| masklinn wrote:
| > Man, this is completely unrelated problem.
|
| You assert that you do not want this on grounds of
| clarity. It is not an unrelated problem to point out that
| C has numerous obscurity issues significantly worse than
| this could ever be in the language right now.
|
| > Implicit operator overload is just a bad design.
|
| That's at best a bunch of words arranged nonsensically,
| and at worst an assertion that you want to remove
| arithmetic operators from the language?
|
| > Integer promotion has advantages and disadvantages,
| especially in a language like C where you often use 8bit
| or 16bit types for memory optimization/alignment reasons.
|
| It's mostly a major actual source of obscurity and bugs.
| bluecalm wrote:
| You are not arguing in good faith but just in case I will
| point out what you are missing:
|
| 1)Implicit operator overload is a bad design in case of
| pointers and objects because a.b and a->b are both
| readable, easy to type and short.
|
| 2)Integer promotion is not as simple because requiring
| explicit promotion makes a holy unreadable mess out of
| your code in the simplest of cases.
|
| 2) is demonstrated many times by mongo code lines in Java
| with all the explicit casts. This is also the reason
| Python has implicit promotion for its number type. You
| sacrifice something to get something unlike in 1) where
| you only lose for no gain what so over.
| masklinn wrote:
| > You are not arguing in good faith
|
| You're just not being honest.
|
| > 1)Implicit operator overload is a bad design in case of
| pointers and objects because a.b and a->b are both
| readable, easy to type and short.
|
| That's just a baseless assertion. Here I can do the same:
| implicit overloading is a great design in case of
| pointers and objects because a.b is always unambiguous
| and uniform, and -> is a harder to read and type extra
| operator which has no justification.
|
| And then obviously your assertion can be used exactly the
| same way to similarly assert that every numeric type
| should have its own set of arithmetic operators, after
| all u4+ is also readable, easy to type, and short.
|
| > 2)Integer promotion is not as simple because requiring
| explicit promotion makes a holy unreadable mess out of
| your code in the simplest of cases.
|
| Integer promotion is much simpler because it's literally
| a never-ending source of bugs.
|
| > This is also the reason Python has implicit promotion
| for its number type.
|
| Python does not have implicit promotion for its number
| type, at best Python 2 had that for performance reasons
| (definitely not "mongo code lines with all the explicit
| casts" which it could not care less about), and in
| reality that was not even the case because it does not
| corrupt your data upfront as C does.
| adrian_b wrote:
| It is not that simple, because in C you may chain a great
| number of prefix and postfix operators.
|
| It is frequent to have multiple "*", "[]", "." and "->".
|
| Now you have the simple rule of executing first the postfix
| operators from left to right, then the prefix operators from
| right to left.
|
| If some special rules had to be invented to avoid writing the
| parentheses in "(*x).y", after adding several "*", "[]" and
| "." it would become impossible to understand the right
| evaluation order.
|
| When all of "*", "[]" and "." are postfix, they are just
| executed in order from left to right, which is easy to
| understand.
|
| While sometimes auto-dereferencing a pointer would be
| convenient, in C you want frequently to get the value of a
| link, or to do pointer arithmetic. With auto-dereferencing,
| some new ways of using an "address of" operator would have to
| be invented, which are unlikely to be more simple than the
| current rules.
|
| Like I have said, the 2 languages that have introduced the
| concept of pointers were Euler, with explicit dereferencing,
| and CPL, with implicit auto-dereferencing.
|
| Both are valid ways to design a programming language, but in
| both case a lot of rules must be added to cover all the use
| cases, which would have to be more complex in the languages
| with auto-dereferencing, so these languages usually solve
| this problem lazily, by just prohibiting some uses, e.g. by
| prohibiting pointer arithmetic.
| tsimionescu wrote:
| I believe GP means that "a.b" should be enough for pointers
| as well, you don't need "a->b" or "(*a).b". It's not like
| pointers can have fields in C, so the meaning would have
| been unambiguous.
| adrian_b wrote:
| Sorry, I had posted a partial reply before finishing
| writing the complete one.
|
| As I have written above, a language with implicit
| dereferencing needs additional syntactic means for
| denoting the cases when the values of the pointers are
| needed, e.g. for doing pointer arithmetic, which is
| frequent in C.
|
| If dereferencing would have been made implicit, that
| would have required a large number of changes in the
| language. C++ has introduced pointers with implicit
| dereferencing, i.e. what C++ calls references, but due to
| the fact that the other syntax changes that are needed
| have not been made, because they would break
| compatibility, the C++ references can replace C pointers
| only in a subset of their uses.
| dataflow wrote:
| > If dereferencing would have been made implicit
|
| You're misunderstanding the comment. They aren't asking
| for implicit derefs. They're asking for explicit derefs,
| using * or . instead of * or ->
| psd1 wrote:
| Your and GP's make no sense unless the reader knows that
| * is a markdown directive and infers where you typed
| them.
|
| Which is ironic when discussing overloading!
| fanf2 wrote:
| Hacker News does not use Markdown.
| OJFord wrote:
| No, but it does use: *
|
| for italics, which sometimes causes a comment to go
| haywire because someone uses it to reference a footnote
| or otherwise drops it in mid-sentence, with a matching
| closing one, not intending italics.
|
| (Up-thread I think it probably was like that when they
| commented, but has since been fixed.)
| wruza wrote:
| Btw, you can now(?) escape * in a paragraph with \\*.
| OJFord wrote:
| Yes, it's also automatic in some cases - originally my
| comment had an attempt at a joke example of it, but it
| was caught and didn't work. It was definitely improved
| relatively recently.
| masklinn wrote:
| While that's technically true, it does use a severely cut
| down version thereof which is worse in every way: it only
| supports paragraphs, code blocks, and emphasis so the
| ability to format is extremely limited but the emphasis
| can still screw you over, which requires an explicit
| preview (or posting) to notice.
|
| And I think escaping emphasis was only introduced
| somewhat recently? I do remember that for the longest
| time you basically had to trick HN into not breaking your
| comments by using a different character in stead.
| dataflow wrote:
| In confused, where in my comment does the Markdown syntax
| come into play? You're not seeing italics or backslashes
| are you?
| psd1 wrote:
| I see now - Hacki renders italics, but the browser
| doesn't.
|
| Excuse my confusion, this possibility didn't occur to me.
| adrian_b wrote:
| With explicit derefs, if "*x.y" is taken to mean
| "(*x).y", then which is the meaning of
| "****x1.x2[7].x3.x4[9].x5"?
|
| > "a.b" should be enough for pointers as well,
|
| I have interpreted this to mean implicit deref, as there
| is no "*" (could be a formatting problem).
| dataflow wrote:
| I think you're still misunderstanding the proposal. What
| are the types of your variables? This discussion makes no
| sense without type information. We're defining the
| meaning of . for pointers here. You seem to be
| misunderstanding the proposal as being purely a textual
| transformation that ignores types?
|
| The proposal is literally: "If you see . and the left
| operand is a pointer, pretend the . was -> instead,
| because otherwise the code is already invalid."
| adrian_b wrote:
| OK, I believe that you are right and if implicit
| dereferencing had been done only when this is the only
| interpretation that leads to a valid expression, then
| "->" would not have been necessary.
|
| However, I assume that this would have been a too complex
| solution for compilers that had to work in a few tens of
| kilobytes of memory, while a postfix "*", as already used
| a decade before C, would have been a trivial solution.
| masklinn wrote:
| > However, I assume that this would have been a too
| complex solution for compilers that had to work in a few
| tens of kilobytes of memory
|
| It's literally the same complexity as the type checking
| compilers already do to tell you that your `.` does not
| work because the LHS is a pointer not a struct.
| tsimionescu wrote:
| No one here is proposing implicit dereferencing
| (everywhere), the proposal is just to make the syntax
| `pointer.field` have the exact same meaning that
| `pointer->field` has in C today. In all other places, the
| current syntax and semantics would stay the same.
|
| Since in all situations where pointer->field is valid
| pointer.valid is an explicit error in C today, this would
| have been very much doable without major changes in
| compiler or language implementation.
|
| Of course, at C's level of abstraction, and given the
| speed limitations of the day, the syntax difference
| between -> and . may well be argued to have been helpful
| instead of harmful.
|
| And yes, the same could not be said for C++, where you
| can implement dereferencing for your own type and get a
| variable where both `a.b` and `a->b` are valid and have
| different meanings. This is anyway not a proposal for
| changing C (or C++) today, merely a "what if" discussion
| about how C could have been designed differently.
| loup-vaillant wrote:
| > _As I have written above, a language with implicit
| dereferencing needs additional syntactic means for
| denoting the cases when the values of the pointers are
| needed, e.g. for doing pointer arithmetic, which is
| frequent in C._
|
| No it doesn't. Let's take this example in valid C:
| struct my_struct { int field }; struct my_struct s
| = { .field = 42 }; struct my_struct *p = &s;
| printf("direct : %d", s.field); printf("pointer:
| %d", p->field); printf("address: %x", p);
|
| What is being proposed here is to make _that_ code valid:
| struct my_struct { int field }; struct my_struct s
| = { .field = 42 }; struct my_struct *p = &s;
| printf("direct : %d", s.field); printf("pointer:
| %d", p.field); // note the use of a dot here
| printf("address: %x", p);
|
| That is, the naked p is still to be interpreted as what
| it is: a pointer. It's just that when we write `a.b`, the
| language would first check the type of `a`, then
| dereference it as many times as necessary to get to the
| underlying struct, and then access its field. For
| instance: struct my_struct { int field };
| struct my_struct s = { .field = 42 }; struct
| my_struct *p = &s; struct my_struct **pp =
| &p; struct my_struct ***ppp = &pp;
|
| Now let's see how this automatic indirection would work:
| // All would print the same value printf("%d",
| ppp.field); printf("%d", pp .field);
| printf("%d", p .field); printf("%d", s .field);
| // We can still use explicit indirections
| printf("%d", (*ppp ).field); printf("%d", (**ppp
| ).field); printf("%d", (***ppp).field);
| printf("%d", (*pp ).field); printf("%d", (**pp
| ).field); printf("%d", (*p ).field);
|
| We can still get to the actual addresses no problem:
| printf("p: %x", p); printf("p: %x", *pp);
| printf("p: %x", **ppp); printf("pp: %x", pp);
| printf("pp: %x", *ppp); printf("ppp: %x",
| ppp);
|
| Note that we can play with the & operator too. In valid C
| we can do this already: printf("s.field:
| %d", s.field); printf("s.field: %d", (*&s).field);
| printf("s.field: %d", (**&&s).field);
| printf("s.field: %d", (***&&&s).field);
|
| With automatic indirection the following would be valid
| too: printf("s.field: %d", (&s).field);
| printf("s.field: %d", (&&s).field);
| printf("s.field: %d", (&&&s).field);
|
| ---
|
| The kicker here is that the decision on whether an access
| to a struct member requires dereferencing the pointer or
| not, is not done at parsing time. It's done at type
| checking time. And by the way, in standard C the decision
| to give you an error or not is already done at type
| checking time. All this to say, this would be a fairly
| benign change to compilers.
|
| Now would _users_ get confused? Possibly. With the
| conflation of pointers and arrays, the following would be
| equivalent: array.field
| (*array).field array[0].field
|
| Looks nifty to some perhaps, but some people really
| meant: array[i].field
|
| and forgot to write the index.
| flohofwoe wrote:
| I really prefer that '.' and '->' remain separate,
| because it makes it immediately clear when a potentially
| expensive pointer derefence is happening:
| x = a->b->c->d->e;
|
| ...is a pointer-hunting-nightmare / potential cache-miss-
| galore. x = a.b.c.d.e;
|
| ...no problem, the whole chain is resolved at compile
| time into a single offset and results in at most one
| memory access. x = a.b.c->d.e;
|
| ...makes it immediately clear that c->d is a pointer
| access and everything else isn't.
|
| PS: ...and of course C++ messed this simple rule up with
| the introduction of references.
| nuancebydefault wrote:
| When stepping up from C to C++, it feels ultimately
| unlogical to use an ampersand to indicate a reference in
| a declaration, while in an assigment or actual parameter
| it means address of. Where they out of special chars?
| Snarwin wrote:
| Interestingly, C already does this for function calls:
| "fptr()" is considered equivalent to "(*fptr)()".
| kps wrote:
| A mistake, IMO; I want to be able to see right away whether
| a call target is static or dynamic.
| WalterBright wrote:
| The thing is, the `->` operator in C is completely unnecessary.
| `.` can be used instead. The compiler can distinguish by
| looking to see if the lvalue is a pointer or a value.
|
| The result makes it much easier to refactor code. Ever try
| replacing a value with a pointer in C? Arrghh.
| paulddraper wrote:
| I think it is debatable on whether struct property access and
| pointer access should appear the same.
|
| * Performance. Pointer access is an order of magnitude more
| expensive.
|
| * Errors. Pointer access can fail (in particular, the NULL
| pointer).
| WalterBright wrote:
| It may be debatable, but in D we've used it for 20 years
| and problems with it have yet to crop up. And indeed, it
| makes refactoring code far easier.
| paulddraper wrote:
| Not directly to syntax, but D null pointer safety is
| weird IMO.
|
| It checks array access bounds, but segfaults for null
| pointers. Seems an odd choice, and there are multiple
| discussions of people saying the same.
| WalterBright wrote:
| Null pointers are automatically checked by the hardware
| (seg fault). Adding another runtime check is redundant.
|
| Yes, I know, adding a huge fixed offset to the pointer
| can push it past the null protected pages.
| brundolf wrote:
| Rust makes them the same too (though its type system
| eliminates the fallibility issue)
| _3u10 wrote:
| The stack is not some magical location in RAM that is
| faster, and in any case you can have a pointer to the
| stack.
|
| It's super common to define a struct on the stack and then
| pass a pointer to an init function to initialize the value
| that is on the stack.
|
| Sometimes pointers are faster because you don't have to
| copy the entire struct.
|
| What largely determines the performance of values vs.
| pointers is whether that location in RAM is cached, and
| whether you need to allocate memory on the heap.
| wruza wrote:
| I wanted this (and few more dozens of things) most of the
| time when I still wanted to write C. Good times.
| d-lisp wrote:
| I have the feeling the generalized "For" is nice because it
| allows for multiple initializers in a compact manner, how does
| for I from 0 to N by 5 deals with this ?
|
| e.g. for(i=0,j=N.length;i<j;i++)
| bmicraft wrote:
| This should be equivalent: for i from 0 to
| N.length [by 1]
| jandrese wrote:
| > that would have been "x*.y", and "->", would not have been
| needed.
|
| Arguably that syntax would have been prone to a lot of
| unintended pointer multiplication due to syntax error.
| loup-vaillant wrote:
| Or we could use a different operator for pointer indirection
| and multiplication? There's also the pointer/array conflation
| that could cause some confusion.
| karmakaze wrote:
| If there weren't already connotations with '@' it would be
| natural for dereferencing--it's what's 'at' an address.
| shiomiru wrote:
| Interesting, I've always thought it's & pronounced as Latin `et',
| which sounds like `at', so &x gives a pointer that "points at" x.
|
| Also, the "near on the keyboard" idea doesn't make sense anyway
| because C was developed on a bit-paired tty33 where the two
| symbols are not that close to each other.
| seydor wrote:
| "address of" "adresaf" "andresanf" "anpresand"
| rpz wrote:
| :) we think similarly. I came here to post &
| and anddress
| Findecanor wrote:
| > anddress
|
| I will remember it as the "Ursula" operator from here on
___________________________________________________________________
(page generated 2023-10-10 23:02 UTC)