Live data from Hacker News

Pointers in C (2010)

boredzo.org

41–50 of 113 posts

Re: Pointers in C (2010)

#42

Earlier quoted context omitted.

> Is there a valid use case for doing pointer arithmetic on a void pointer? It just seems so disgusting on the surface. Did someone just really not want to bother casting to uint8_t * ? As a side note, there was a debate whether casting to `uint8_t * ` is a strict-aliasing issue (As `uint8_t` and `char` are not guarenteed to be the same type, and so the compiler isn't required to treat them as such). That said, you'r…

> `uint8_t` and `char` are not guarenteed to be the same type Remember that `char`, `signed char` and `unsigned char` are the different types, even though `char` takes the same range of values as either `signed char` or `unsigned char`. The typedef `uint8_t` is usually set to `unsigned char`, not `char`, even on systems where `char` is unsigned. Partly this reflects the fact that `char` is usually used to represent a…

> I believe all current major implementations typedef `uint8_t` to `unsigned char`

That can't be right, because CHAR_BIT is not always 8.

Re: Pointers in C (2010)

#43
post #39

Earlier quoted context omitted.

Casting to uint8_t* is not portable either, so it's not particularly better than using compiler extensions that let you increment void*.

"char" is portable and by definition sizeof(char) == 1 and on top of that char pointers can alias other types. If I could time travel and influence the design of C the first things I'd do is change switch to break by default. The 2nd thing I'd do is rename "char" into "byte" since that's effectively what it is (and it's seldom a character these days since we often use UTF-8 or other multi-byte encodings).

> The 2nd thing I'd do is rename "char" into "byte" since that's effectively what it is

This isn't always true. See machines where CHAR_BIT > 8.

Re: Pointers in C (2010)

#44
post #2

I always wonder what makes pointers so difficult for some. So far I have always been able to explain it to people by drawing a linear memory space and then showing how different types are allocated. It seems to me that pointers are one the easier concepts in programming.

I believe because it is taught the wrong way and with a confusing notation.

We do int ptr instead of int ptr and talk about memory instead of just saying: "It is simply a box containing 1 value, we can also make a box containing a box containing the value."

Luckily, I don't do C.

Re: Pointers in C (2010)

#45
post #22
post #2

I always wonder what makes pointers so difficult for some. So far I have always been able to explain it to people by drawing a linear memory space and then showing how different types are allocated. It seems to me that pointers are one the easier concepts in programming.

My guess is, people are trying to keep variables the primary concept, and explain pointers on top of that. Hence, ‘boxes’ again crop up in an explanation of pointers. For me, everything became much more clear when I realized that the heap memory stands on its own as a concept, being a big pile of bytes instead of ‘boxes’—and implicit allocation/deallocation of variables is just a thin veil on top (muddying the matter…

That's funny, I made a completely contrarian comment: I believe there is not enough talk about boxes and too much about irrelevant memory magic!

Re: Pointers in C (2010)

#46
post #26
post #9

I joked the other day to a co-worker, currently working full time in Python, that you get used to the list comprehension and other nice things of Python so much, that you'll never be able to go back to gnarlier languages like Java/C. It's just too nice. You can get python to run really fast nowadays and if you can't, you still got nim.

C# and Java 8 (I believe) provide functional patterns. e.g. in C# the ToLower function which takes a string and returns a string can be used like: var lowercaseIds = ids.Select(ToLower)

You believe correctly, but naturally, it's a lot more verbose:

  var lowercaseIds = ids.stream().map(String::toLowerCase);
and an additional

  .collect(Collectors.toList())
if you don't want a Stream instance. (var is Java 10, though I believe it should not be used in production code, ever)

Re: Pointers in C (2010)

#47

Earlier quoted context omitted.

> `uint8_t` and `char` are not guarenteed to be the same type Remember that `char`, `signed char` and `unsigned char` are the different types, even though `char` takes the same range of values as either `signed char` or `unsigned char`. The typedef `uint8_t` is usually set to `unsigned char`, not `char`, even on systems where `char` is unsigned. Partly this reflects the fact that `char` is usually used to represent a…

> I believe all current major implementations typedef `uint8_t` to `unsigned char` That can't be right, because CHAR_BIT is not always 8.

Practically speaking, for most people these days it is. POSIX specifies 8 bits and windows uses it. If you're working with a larger bit char, you're most likely well aware of it (offhand, some TI embedded chips are the only ones I know of, and even theyre rare!)

Re: Pointers in C (2010)

#49
post #12
post #5

I don’t have my copy at hand, but Expert C Programming: Deep C Secrets has the best coverage of pointers and arrays I’ve seen. In particular, it supplies a useful algorithm for decoding all pointer declarations such as functions that return function pointers. https://www.goodreads.com/book/show/198207

I'm guessing that the algorithm may be the spiral rule: http://c-faq.com/decl/spiral.anderson.html

The spiral rule is wrong. It breaks for things as simple as arrays of arrays.

    //        +---------+
    //        |   +--+  |
    //        |   ^  |  |
        int /*|*/ aa[2][3];
    //   ^    |      |  |
    //   |    +------+  |
    //   +--------------+
The correct result is "aa is a (2-element) array of a (3-element) array of ints".

To get the correct interpretation, you have to know that the spiral has to avoid the "int" element after passing through "[2]". This defeats the purpose of the spiral, since the line sometimes goes through the element and sometimes it doesn't. For example if it were "int * paa[2][3]" instead, the correct order is { [2]; [3];* ; int }. Note how the star is first avoided and comes after [3]. A 2-array of a 3-array of pointer to int.

How would you know when the spiral "avoids" the element on the left and when it doesn't? Well, you need to know the declaration grammar to know that [] and () bind stronger than the thing on the left, so you need to process those first. But if you know this, drawing a spiral is redundant, because you already parsed the thing.

I think the spiral rule is inherently wrong and should not be reposted as a helpful cheat-sheet for parsing C/C++ declaration syntax.

Re: Pointers in C (2010)

#50
post #12

Earlier quoted context omitted.

I'm guessing that the algorithm may be the spiral rule: http://c-faq.com/decl/spiral.anderson.html

The spiral rule is wrong. It breaks for things as simple as arrays of arrays. // +---------+ // | +--+ | // | ^ | | int /*|*/ aa[2][3]; // ^ | | | // | +------+ | // +--------------+ The correct result is "aa is a (2-element) array of a (3-element) array of ints". To get the correct interpretation, you have to know that the spiral has to avoid the "int" element after passing through "[2]". This defeats the purpose of…

A good exercise is to then guess why the spiral rule seems to work most of the time even though it is inherently wrong.

The reason is that some types that are syntactically valid are forbidden by C/C++. You cannot have a function returning a function. A function returning an array. An array of functions. You can only have a pointer to these (function returning a pointer to function/array or an array of pointer to functions), and then they need to be correctly parenthesized. Then the spiral rule works because you only have two elements in a parenthesis and you can just go right and then go left... unless you have arrays of arrays which are legal, and then it doesn't work.

But the more correct rule would be to go right and parse all [] and () inside the current parenthesis level, then go parse the * -s (including const/volatile) on the left. Then repeat for outer parenthesis levels.

Post reply on HN