16 ms·
I checked the section "Interlude: Arrays" because the relationship between pointers and arrays in C is a major sticking point. It claims that, given a declarat
by _kst_ 8y ago
I checked the section "Interlude: Arrays" because the relationship between pointers and arrays in C is a major sticking point.
It claims that, given a declaration
int array[] = { 45, 67, 89 };
the expressions "array", "&array", and "&array[0]" are all equivalent. They are not. "&array" and "&array[0]" both refer to the same memory location, but they're of different types.
In the next section:
"By the way, though sizeof(void) is illegal, void pointers are incremented or decremented by 1 byte."
Arithmetic on void pointers is a gcc-specific extension (also supported by some other compilers). It's a constraint violation in standard C.
I don't think this is the "best" article on pointers in C.
I usually recommend section 6 of the comp.lang.c FAQ, http://www.c-faq.com/ http://www.c-faq.com/
- jandrese 8y agoIs 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 for the array types, I think maybe the article is really trying to say that they'll all compile down to the same thing in the end (probably...compilers can be weird sometimes).
- torstenvl 8y agoCasting to uint8_t* is not portable either, so it's not particularly better than using compiler extensions that let you increment void*.
- simias 8y ago"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).
- saagarjha 8y ago> 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.
- Sean1708 8y agoI always thought that 1 char was exactly 1 byte, but that 1 byte was not necessarily 8 bits?
- saagarjha 8y agoI think from a C standards point of view, that's true; I was using the general convention of 1 byte=8 bits, but char being one or more of these bytes. Hence CHAR_BIT is the number of bits in a char, and sizeof gives the number of chars that would fit in the specified type.
- simias 8y agoA byte is the smallest addressable memory unit, nothing more, nothing less. It's true that on most modern machines it's always equal to 8 bits (and it's mandated by POSIX AFAIK) but that's orthogonal. In French when talking about storage capacity we use "octet" instead of "byte", I always thought that made more literal sense (if you have a 1megabyte memory on a system where CHAR_BITS is 16, do you have 8 or 16 megabits?).
- vardump 8y agoThere are bit-addressable CPUs and DSPs. Examples are many microcontrollers (part of the memory accessible in bit-addressable windows), and famous TMS34010 (https://en.wikipedia.org/wiki/TMS34010 https://en.wikipedia.org/wiki/TMS34010). 4-bit CPUs (like the one in your toothbrush or thermometer) can also of course address 4-bit "words", "bytes" or nibbles. So 8 bits might not be the smallest addressable memory unit.
- DSMan195276 8y ago> 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're correct that you can always cast to `char * ` in this case as `char * ` is allowed to alias anything. I do agree pointer arithematic on `void * ` a bit messy, I think the intention was just as a convenience thing, but it can definitely be abused. > As for the array types, I think maybe the article is really trying to say that they'll all compile down to the same thing in the end (probably...compilers can be weird sometimes). I donno, I've read this page before and think the author genuinely doesn't know about pointers to arrays - if they do they've done a good job of pretending they don't exist. They are not mentioned anywhere on the page (Besides the part that says they're are all the same), and near the top the author talks about parentheses in variable declarations and says: > This is not useful for anything, except to declare function pointers (described later). Which anybody who has used a pointer to an array will know is not true, as you have to use parentheses to differentiate between a pointer to an array from an array of pointers.
- quietbritishjim 8y ago> `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 actual characters, while the other two types are usually used to represent integers that take the same amount of memory as `char`. The standard technically does not allow `uint8_t` to be `char` [1], although this requires an extremely pedantic reading. Anyway, if you replace `char` with `unsigned char` in your comment then it's correct. I believe all current major implementations typedef `uint8_t` to `unsigned char`, but that's not guaranteed and even old implementations of GCC had a different type. `unsigned char` satisfies the same relaxed aliasing rule as `char` [2] but `uint8_t` may not. [1] https://stackoverflow.com/a/16002781 https://stackoverflow.com/a/16002781 [2] https://stackoverflow.com/a/40575162 https://stackoverflow.com/a/40575162
- emmelaich 8y agoThe C faq presents as supposedly common questions and answers without saying what a pointer is. In contrast I really like the posts definition. > A pointer is a memory address. Not perfect but for concision and accuracy it cannot be beat.
- Stratoscope 8y agoWell, it's concise, but it leaves out something important. A C pointer has both a memory address and the type of whatever it believes it points to. The latter is what makes C-style pointer arithmetic possible, because if you know the type, you know its size too.
- deleted 8y ago[deleted]
- kazinator 8y agoC pointers being typed is absolutely central. Firstly, because a pointer is typed, when we dereference it, the memory location is accessed properly as the type. We don't have to put anything in the expression to say "please access the memory as 'struct foo', or a 'double'". Secondly, arithmetic on pointers for array-like manipulation uses correct displacements for the size of the type. Thirdly, we get error checking: there is a good amount of resistance in the language against mixing up types. If we convert one type of pointer to another without a cast, we get a diagnostic. All these aspects are a key aspect of what separates C from assembly language.
- deleted 8y ago[deleted]
- torstenvl 8y ago> C pointers being typed is absolutely central. No it isn't. The rest of your post shows why. > Firstly, because a pointer is typed, when we dereference it Nonsensical and circular. > Secondly, arithmetic on pointers... Nonsensical and circular. > Thirdly, we get error checking: there is a good amount of resistance in the language against mixing up types. If we convert one type of pointer... Circular. Every single one of your points about why this is an important property of pointers presupposes that the reader knows what a pointer is and how it works. It's a fundamental truism that you can't introduce, explain, and define a term using the term itself. The OP's introduction does not suffer from this problem, which is why it is superior to your proposal. (Edit: You all can downvote me all you want, but you're still objectively wrong.)
- Stratoscope 8y ago> "&array" and "&array[0]" both refer to the same memory location, but they're of different types. Indeed. And isn't this what makes the classic "countof" macro possible? The macro returns the number of elements in an array, calculating this by dividing the size of the array by the size of the first element: #define countof( array ) ( sizeof(array) / sizeof((array)[0]) )
- monk_e_boy 8y agoDude, I've just been asked to teach c pointers and this was super helpful. Got a good c++ FAQ? :)
- plasticchris 8y agoMarshall Cline made a good one, here's a mirror, the original seems down: http://www.dietmar-kuehl.de/mirror/c++-faq/references.html http://www.dietmar-kuehl.de/mirror/c++-faq/references.html
- klmr 8y agoMarshall Cline’s FAQ been absorbed by the “official” C++ FAQ: https://isocpp.org/faq https://isocpp.org/faq
- vram22 8y agoMarshall Cline's C++ FAQ is really, really good, IMO. I had read it some years ago, I think both the online version and the book, even though I've not really worked on C++ in projects. It goes into good depth and detail, not only on C++ language features and points, but also a lot into OOP/OOAD topics. Things like why you should (sometimes) push code from the client to the server - push in the sense of shift, not in the sense of mobile code, how old code can call new code - that didn't exist when the old code was written - don't remember the full details of that one right now, it may be via virtual functions and inheritance), and many more such things, a lot of them very useful. And all written in a fun, engaging style.
- deogeo 8y ago> "&array" and "&array[0]" both refer to the same memory location, but they're of different types. "&array[0]" also does a dereference, which may cause undefined behaviour if array is null or invalid. You can get fun stuff like the optimizer omitting null checks later on.
- DerekL 8y agoInteresting. In C, “&array[0]“ is the same thing as “(array + 0)”, but in my copy of the C11 draft standard, I can't find anything about adding zero to a null pointer.