|
I would recommend against taking a C++ class to help you learn C. The languages are technically distinct but similar enough that I think you will be confused trying to learn that way. There a few subtle behavioral differences in the seemingly overlapping parts, but more importantly, even a good C++ class will be largely teaching the ++, not the C. And as it turns out, while C++ might be "more complicated" than Java or some of the Lisps, it's hard to argue that C is. The language is actually pretty dang simple. This means that people use it to do some gnarly things, which is where its intimidating reputation comes from. (Also because teaching pointers is apparently rocket science for some reason that I haven't been able to figure out.) If it were 20 years ago, all you'd need to do is work your way through K&R, but the language has been updated twice since then, and I don't know of a good equivalent for the new standard. Maybe someone else can chime in with a recommendation.
|
# ? Jul 17, 2014 08:26 |
|
|
# ? Jun 7, 2024 22:20 |
|
What classes you take shouldn't dictate what languages you end up knowing. If you want to learn C, then learn it. That has nothing to do with taking a class.
|
# ? Jul 17, 2014 10:31 |
|
C is much easier to understand in its entirety than C++. Even if it's dated, if you're interested in learning C I'd highly recommend picking up The C Programming Language, 2nd Edition. The book is no wider than your thumb and covers the entirely of the language, obviously excluding the more recent developments. Compare this to the C++ "Primer" book which is a good 6 times thicker and can be used as a weapon in dire situations. Sadly I'm not sure what would be a good recommendation for learning modern C though. The most modern book focusing exclusively on C that I own was printed over 14 years ago. edit: I'm really just re-hashing what GrumpyDoctor said aren't I? space kobold fucked around with this message at 11:53 on Jul 17, 2014 |
# ? Jul 17, 2014 11:40 |
|
Ask the professor to see if they'll be teaching basic C as you go along in Operating Systems, since they don't teach a C course? It doesn't make sense to offer a course with prereq's that no student could ever learn.
|
# ? Jul 17, 2014 13:14 |
|
It'll be probably be easier to learn C ahead of time rather than while also learning how I/O schedulers work. K&R 2E won't teach you modern C idioms, but it'll teach you well enough to do coursework. Just remember to check your return values!
|
# ? Jul 17, 2014 14:16 |
|
Xun posted:Not sure if this is the right place to ask, but next semester I'm required to take Operating Systems, which uses C. I only know java and python and I'm shaky at C++ at best. I'm feeling super unprepared because so far my programming education have been a progression of Java -> Java/LISP(???) -> A tiny bit of assembly and some C++ -> C As mentioned, there's pretty big differences between "C" and "C++" style programming, there's a different set of programming idioms and stuff. Assuming you want to learn C, the K&R book is the classic. I'm generally of the opinion that programming is mostly language-agnostic, it's about breaking down your problem into discrete steps and then applying the tools your language gives you to solve that. Java is ultimately a distant descendent of C, the roughness of it (pointers/pointer arithmetic, the stdlib, etc) might be a bit of a slap but if you do OK at Java you'll eventually adapt to the syntax and behavior. It's something you'll probably have to do sooner or later given how much stuff uses C as a jumping-off point. If you're worried about it, do some assignments using the stdlib that do stuff like timing, IO, etc and that should give you an introduction to the C style idioms. Paul MaudDib fucked around with this message at 22:39 on Jul 18, 2014 |
# ? Jul 18, 2014 22:30 |
|
I am trying to understand some of the differences between the different constant types when defining a function in a class. Lets assume all this code is written within a class definition. Please let me know if I have misunderstood anything, I have a feeling I got something wrong.code:
code:
code:
Xeom fucked around with this message at 22:13 on Jul 19, 2014 |
# ? Jul 19, 2014 21:17 |
|
The bit with const in the middle just means that the function can be called on class instances that are themselves const, and that the this pointer inside the function body will be a pointer to const. It's kinda weird that your member function is returning *this but also returning type int&.
|
# ? Jul 19, 2014 21:49 |
Xeom posted:
This should fail to compile. Inside the function, this is of type const classtype *, meaning that the type of *this will be const classtype. If you attempt to return a reference to that, the reference must of of type const classtype & because the object in question is const. And it's not a "low level constant", you're declaring the function as being const.
|
|
# ? Jul 19, 2014 22:36 |
|
Vanadium posted:The bit with const in the middle just means that the function can be called on class instances that are themselves const, and that the this pointer inside the function body will be a pointer to const. Sorry don't know what I was thinking when I wrote the type, its fixed now. nielsm posted:This should fail to compile. Ok I was hoping it wouldn't compile. I was hoping that it could access objects(const and non), but not write to them. I am get your first point, but not your second. It sounds like you are saying that my third example does actually compile? I was hoping that it also would not compile. Aren't you assigning a new value to a constant object? Xeom fucked around with this message at 23:08 on Jul 19, 2014 |
# ? Jul 19, 2014 22:50 |
|
In OSX, if I'm trying to .open a file on my desktop, what do I enter as the path? "Users/Me/Desktop/file.txt" isn't it.
|
# ? Jul 19, 2014 22:56 |
|
PRADA SLUT posted:In OSX, if I'm trying to .open a file on my desktop, what do I enter as the path? "Users/Me/Desktop/file.txt" isn't it. /Users/Me/Desktop/file.txt
|
# ? Jul 19, 2014 22:58 |
|
One other question. I'm writing a program that has the user input the directory of a .txt file (string location) and then it parses the data and does something. It's supposed to kill the program if the user enters an incorrect directory.code:
|
# ? Jul 20, 2014 04:36 |
|
PRADA SLUT posted:One other question. I'm writing a program that has the user input the directory of a .txt file (string location) and then it parses the data and does something. It's supposed to kill the program if the user enters an incorrect directory. '/' is a valid path, though. It's the root directory. You probably have a folder 'a' in your CWD.
|
# ? Jul 20, 2014 05:14 |
|
Xeom posted:I am trying to understand some of the differences between the different constant types when defining a function in a class. Lets assume all this code is written within a class definition. Please let me know if I have misunderstood anything, I have a feeling I got something wrong. The basic thing to understand is the difference between a constant pointer and a pointer to a constant. code:
Two more traps for the unwary: code:
Zopotantor fucked around with this message at 08:57 on Jul 20, 2014 |
# ? Jul 20, 2014 08:54 |
|
Thanks Zopotantor. I did a few examples functions and I think I have a solid grasp on it now. I understood the differences between a constant pointer and a pointer to a constant, but for some reason when it related to functions I sort of got thrown off.
|
# ? Jul 20, 2014 21:21 |
|
I'm trying to call a member function on an unknown type, which is a template. This works:code:
|
# ? Jul 21, 2014 20:15 |
|
Stupid type-punning/aliasing question:C++ code:
(Toy code specifically to demonstrate the question) Now, if I understand this correctly if I write to the structures and then attempt to read from the char *, it's perfectly legal for the writes to not go through, or to be re-ordered with respect to access of the underlying char * buffer. Also, if I write to the buffer it's legal that a read from the structure won't reflect that. I can live with those restrictions. The question is: Is the cast itself undefined behavior that can be elided by a compiler, or is a read-only usage like that guaranteed to do what I expect? Do I need a sequence point before the read to prevent re-ordering? (In this specific example I don't think so, because the compiler can't assume expected != 1, but there's probably ways to write this where that's not true) I'd prefer to avoid memcpy since this is for embedded - and a union is problematic due to the multitude of data-structs that could be returned - either my serial code would have to know about all of them, or I'd have to use a caller-supplied buffer that has all the unions.
|
# ? Jul 22, 2014 04:08 |
|
Strict aliasing lets the compiler assume that pointers to different types are never the same object, so mutation of one can't affect what's seen of the other. For your read-only case, there's no ordering constraint that matters, so IMO you should be fine. It seems like with some template magic (containing an inner union type) you should be able to make it work too?
|
# ? Jul 22, 2014 04:18 |
|
Subjunctive posted:Strict aliasing lets the compiler assume that pointers to different types are never the same object, so mutation of one can't affect what's seen of the other. For your read-only case, there's no ordering constraint that matters, so IMO you should be fine. Well the problem is if I've hit UB who the gently caress knows what the compiler will do - if casting results in UB then the actual pointer assignment could be elided leading to not a segfault on embedded because there is no zero-page, so I just end up reading/writing from IO registers bad things happening As far as a union that's also problematic since the serial code is shared so I'd have to either teach it every structure type in on gigantic union or have each subsystem pass-in a buffer/union with the types it knows about, etc. Yeah, it sucks that a copy of a 32 byte structure is something you need to worry about. On a real machine I'd just memcpy to a struct on the stack and call it a day. Also: C code:
Actually, how the hell do you write malloc() without strict-aliasing warnings? Does the pass through void* clear them? Edit: Oh, it's firing the warning on my code because char[] != char *, and as such isn't exempted from strict-aliasing rules. If I add the pointer and a malloc the warning goes away - but does the danger? Am I reading the standard right that the compiler has to assume that type-punning a char * into a struct may alias? I hit the error because on a tiny platform without dynamic allocation I baked the buffersize in. It's easy enough to have char * buf; char _rawbuf[16]; buf=_rawbuf;- I can live with two bytes of overhead much more than 30+. Harik fucked around with this message at 05:34 on Jul 22, 2014 |
# ? Jul 22, 2014 05:15 |
|
Harik posted:Well the problem is if I've hit UB who the gently caress knows what the compiler will do - if casting results in UB then the actual pointer assignment could be elided leading to not a segfault on embedded because there is no zero-page, so I just end up reading/writing from IO registers bad things happening Technically, it would be UB. The only standards-certain thing is to memcpy. I would be very, very surprised if read-only aliasing could ever cause problems, since the ability for the compiler to treat the pointers as unrelated doesn't have any effect on what code it can generate. (I'm not sure how the sockaddr parts of the sockets API can be used without tripping the UB technicalities here, similarly.) malloc gets special treatment (newly allocated objects have no declared type, and take the type of the thing stored into them); I forget which passage in C99. If you're using gcc or clang, "may_alias" on your structure types could be helpful, but you might be giving away a lot of performance elsewhere. Edit: v8 uses this, which I frankly find a bit suspect unless you're verifying codegen every time compiler config or calling source change: C++ code:
Subjunctive fucked around with this message at 11:37 on Jul 22, 2014 |
# ? Jul 22, 2014 11:06 |
|
Subjunctive posted:(I'm not sure how the sockaddr parts of the sockets API can be used without tripping the UB technicalities here, similarly.) C99, 6.5.2.3 posted:One special guarantee is made in order to simplify the use of unions: if a union contains several structures that share a common initial sequence (see below), and if the union object currently contains one of these structures, it is permitted to inspect the common initial part of any of them ... Two structures share a common initial sequence if corresponding members have compatible types ... for a sequence of one or more initial members. Bonfire Lit fucked around with this message at 11:55 on Jul 22, 2014 |
# ? Jul 22, 2014 11:53 |
|
Bonfire Lit posted:There's a special exception for stuff like this, by use of unions. Sure, but sockaddr/sockaddr_in/sockaddr_in6 aren't unions, they're structures that share the same initial layout, right?
|
# ? Jul 22, 2014 13:00 |
|
That's right. But that exception allows you to turn a sockaddr_in (or sockaddr_in6 or whatever) into a sockaddr to pass to bind(2), via a union. bind then can (legally) inspect the sa_family member to figure out what kind of object the sockaddr* it got actually is, and is allowed to cast to that back to its original type. But I'm not a compiler writer so I might be interpreting the standard incorrectly.
|
# ? Jul 22, 2014 13:35 |
|
No, it falls apart on the cast. That's what violates the aliasing rule. Once you cast they are assumed to not alias each other. The language you quoted says that if I had sockaddr and sockaddr_in in a union, I could fill one and read the other -- but only for the sub-fields that made up the common prefix. Writing to one field of a union and reading from another is otherwise undefined.
|
# ? Jul 22, 2014 14:19 |
|
Harik posted:Yeah, it sucks that a copy of a 32 byte structure is something you need to worry about. On a real machine I'd just memcpy to a struct on the stack and call it a day. What uC are you working with where memcpy doesn't work? I do it all day long on Cortex-M and Freescale S08. e: and when you look at the gen'd asm, you see that the actual call to memcpy will get elided in most cases where you're using it for type punning Blotto Skorzany fucked around with this message at 14:22 on Jul 22, 2014 |
# ? Jul 22, 2014 14:20 |
|
Bonfire Lit posted:That's right. But that exception allows you to turn a sockaddr_in (or sockaddr_in6 or whatever) into a sockaddr to pass to bind(2), via a union. bind then can (legally) inspect the sa_family member to figure out what kind of object the sockaddr* it got actually is, and is allowed to cast to that back to its original type. There's a compiler extension called transparent unions that makes this work, standard C doesn't allow it.
|
# ? Jul 22, 2014 14:24 |
|
pseudorandom name posted:There's a compiler extension called transparent unions that makes this work, standard C doesn't allow it. Transparent unions don't even let that work, in the general case. They just let you do overloading at call time, really, and AFAICT it's only legal for the callee to access the same member that was originally set. You still can't take a sockaddr, look at its family, and then cast to the right one safely. (You couldn't put the different flavours of sockaddr into a transparent union either, because they have to have the same size.)
|
# ? Jul 22, 2014 14:35 |
|
Otto Skorzeny posted:e: and when you look at the gen'd asm, you see that the actual call to memcpy will get elided in most cases where you're using it for type punning
|
# ? Jul 22, 2014 15:05 |
|
Incidentally, C99 eventually legalized union type punning, but I don't know whether compilers other than GCC will properly not warn about it when in C99 mode:ISO/IEC 9899:1999 Technical Corrigendum 3 posted:15. Page 073, 6.5.2.3 Cf. http://www.open-std.org/Jtc1/sc22/wg14/www/docs/n1235.pdf
|
# ? Jul 22, 2014 15:16 |
|
Okay. First, the cast itself is not undefined behavior. The aliasing rules apply to accesses (e.g. loads, stores, member accesses), and casts aren't accesses. You are explicitly allowed to cast pointers to arbitrary other pointer types and then cast back (as long as you don't cast a less-aligned pointer to a more-aligned type; that's undefined behavior, but not because of the aliasing rule). Second, GCC is technically correct but probably on inadvisable ground when strictly applying the effective type rule to declared arrays of char, which is an extremely common idiom for embedding arbitrary object storage within a type. Note that C++'s object lifetime rules are okay with doing this as long as you construct the object properly in the storage. (Although C++'s rule is in no way limited to arrays of char.) Third, the C committee isn't really sure how aliasing in unions is supposed to work. I, personally, would agree that the union exceptions should only apply when the l-value is clearly derived from a union member, but the last time I heard, there are committee members who favor a rule about whether there is any union visible in the translation unit. It's a mess. Fourth, memcpys of small constant size are extremely likely to be turned into the obvious load/store sequence; I would not stress about it unless you are using a terrible custom embedded compiler (which probably does not implement type-based aliasing optimizations anyway). Finally, clang explicitly permits "obvious" type-puns that formally violate the strict aliasing rule. If the compiler can see that two pointers obviously overlap, it will give that information precedence over strict-aliasing information, and so still recognize that the pointers alias. This is why clang doesn't bother implementing that warning. Last time I checked, GCC will give the strict-aliasing information precedence, so the warning is prudent for them.
|
# ? Jul 22, 2014 17:31 |
|
I'm looking for some help with some c++ code. I'm brushing up on my pointer arithmetic and I was pointed to this site: http://www.interqiew.com/tests?type=cpp to get some good questions to test myself. I arrived at the following question however, and I have no idea whats going on: code:
The output at the end is 0204 for the record,
|
# ? Jul 22, 2014 17:51 |
|
PiCroft posted:My theory is that it is trying to demonstrate where in memory an object member lies relative to where the object itself lies, so in the case of A, the pointer to the object itself and the pointer to the member m_x within it both point to the same space in memory and thus subtracting one from the other gives 0. This is my theory though, I'd appreciate it if someone could tell me if I'm right. That's correct. B demonstrates that replacing a var in a derived class hides it but the original var still exists, so the ptr is offset for the second var. C has a virtual function, so there is a vtable in its instances and it sits before the vars.
|
# ? Jul 22, 2014 19:53 |
|
Skuto posted:That's correct. So I take it that static int m_n in B doesn't actually take up memory for a B object? I read that a static member variable is a special case because being static makes it a class-level object and not strictly speaking a part of the instance-level object, so a static int in B wouldn't count for memory purposes.
|
# ? Jul 22, 2014 20:19 |
|
PiCroft posted:I'm looking for some help with some c++ code. Man this is a giant-rear end way of showing off offsetof
|
# ? Jul 22, 2014 20:24 |
|
PiCroft posted:So I take it that static int m_n in B doesn't actually take up memory for a B object? I read that a static member variable is a special case because being static makes it a class-level object and not strictly speaking a part of the instance-level object, so a static int in B wouldn't count for memory purposes. That's correct. The static is per-class, so instances don't need a separate copy.
|
# ? Jul 22, 2014 21:09 |
|
Otto Skorzeny posted:What uC are you working with where memcpy doesn't work? I do it all day long on Cortex-M and Freescale S08. You misunderstand - memcpy works just fine, but I've only got 128/256 bytes of RAM depending on the part, so I'm trying to use the data in-place in the receive buffer rather than using more RAM to make a copy. As for your edit: How does the memcpy legally get elided? If I push a structure on the stack and memcpy to it, the compiler will just skip that whole bit and alias the structure to the buffer? That seems problematic.
|
# ? Jul 23, 2014 00:04 |
|
Harik posted:You misunderstand - memcpy works just fine, but I've only got 128/256 bytes of RAM depending on the part, so I'm trying to use the data in-place in the receive buffer rather than using more RAM to make a copy. Cf. http://blog.regehr.org/archives/959 quote:
And also what clang developer and forums user rjmccall said: rjmccall posted:Fourth, memcpys of small constant size are extremely likely to be turned into the obvious load/store sequence; I would not stress about it unless you are using a terrible custom embedded compiler (which probably does not implement type-based aliasing optimizations anyway).
|
# ? Jul 23, 2014 00:07 |
|
Oh, I thought that what he wanted was to return a view into an existing buffer. The relevant loads would then be in other functions, separated in time and compilation unit. (The stores have already happened off in interrupt-service land or whatever.)
|
# ? Jul 23, 2014 00:17 |
|
|
# ? Jun 7, 2024 22:20 |
|
rjmccall posted:aliasing discussion Thanks, that's a lot of info to go through. Holy poo poo, that's great. Gcc 4.8 does that for atmel, I'll do it properly with memcpy and not worry about it anymore, thanks! Edit: goddamn clang is smart enough to get the round-trip right: C code:
Harik fucked around with this message at 00:46 on Jul 23, 2014 |
# ? Jul 23, 2014 00:39 |