|
ExcessBLarg! posted:Unfortunately any sufficiently-developed object system in C ends up relying on non-standards compliant behavior to implement inheritance. Which behaviors are you talking about here?
|
# ? Mar 4, 2013 00:04 |
|
|
# ? Jun 8, 2024 09:27 |
|
pseudorandom name posted:Which behaviors are you talking about here? There's a few ways to do it. Making the "base class" be the first element is probably the most portable. Where it's not the first element, one has to use offsetof to locate the start of the container struct. Since offsetof is part of C90 it should be safe to use so long as the compiler does (and should) implement it. The non-portability comes in that some variants of the macro place a fictitious instance of a struct at address 0, for the purpose of determining the address offset of a struct member. The best way I've seen to achieve this effect is Linux's container_of macro. It differs from most implementations by using GCC's typeof operator (which is non-standard) and pointer assignment to perform type checking as best it can. In short, there's ways of doing it that are reasonably standard-compliant but eschew type checking, and vice-versa. It's not a huge deal, but the fact that there isn't a type-safe standards-compliant version of container_of is one of there reasons why OOP in C is somewhat dicey and ad-hoc.
|
# ? Mar 4, 2013 00:24 |
|
Doesn't C++ have a way to implement template methods only for certain template parameter matchups? i.e. I'm trying to port a some old linear algebra types and make various aspects of it generic, but some things have implementations that are specific to particular row/column counts (i.e. fast inversions, cross product, etc.) I'm trying this: code:
code:
OneEightHundred fucked around with this message at 02:28 on Mar 4, 2013 |
# ? Mar 4, 2013 02:25 |
|
No. You have to specialize the entire class. You might want to consider doing it with template functions instead, which you can specialize. edit: or you can use CRTP to make some mixins. tractor fanatic fucked around with this message at 02:32 on Mar 4, 2013 |
# ? Mar 4, 2013 02:29 |
|
Speaking of which, I've got a 12K LOC numerical program I've written in C99 and as it grows in scope, it's becoming a bit more difficult to manage despite my best efforts to organize things into logical data structures and files. I'm starting to think it might be worthwhile to transition the program to C++ as I make further improvements, especially as there are a number of useful C++ numerical libraries which have been developed recently. I haven't worked with C++ much; any recommendations for where I should start, both in terms of my education and in terms of porting the code?
|
# ? Mar 4, 2013 02:43 |
|
It's pretty straightforward. The first thing to do is to just turn all your source files into C++ files and make sure everything still builds and runs. Once you've done that, it's mostly a matter of cleaning things up. Look at all of your types and start trying to improve encapsulation. Try to split out useful functions that work on on a single object. Functions that create a single object should probably become constructors (or at least static "factory" methods). Functions that destroy a single object should probably become destructors. Functions that clone an existing object should become copy constructors. Other functions that really just work on a single object probably ought to become instance methods on it. Try to make fields private if you can. Introduce getters and setters when it makes sense to. Use new and delete instead of malloc and free. And so on.
|
# ? Mar 4, 2013 03:02 |
|
tractor fanatic posted:No. You have to specialize the entire class. You might want to consider doing it with template functions instead, which you can specialize. code:
The language not supporting it in instance methods seems kind of weird.
|
# ? Mar 4, 2013 03:13 |
|
Oh if you only wanted to enable a function for a certain specialization you can use boost::enable_if. If you don't want to include boost you can make your own using SFINAE. It looks hacky as hell but it prevents a 4x4 matrix from having an inverse function. Or at the very least, add a static_assert to your current inverse method so that it's clear why there's a failure when you try to call inverse on a 4x4 matrix.
|
# ? Mar 4, 2013 03:28 |
|
enable_if is part of the standard library now. If you have that luxury.
|
# ? Mar 4, 2013 04:29 |
|
tractor fanatic posted:Oh if you only wanted to enable a function for a certain specialization you can use boost::enable_if. If you don't want to include boost you can make your own using SFINAE. It looks hacky as hell but it prevents a 4x4 matrix from having an inverse function. Or at the very least, add a static_assert to your current inverse method so that it's clear why there's a failure when you try to call inverse on a 4x4 matrix. enable_if is also in the C++11 standard as std::enable_if (it's equivalent to enable_if_c in boost).
|
# ? Mar 4, 2013 04:32 |
|
rjmccall posted:It's pretty straightforward. And so on. Sounds like a plan!
|
# ? Mar 4, 2013 04:54 |
|
ExcessBLarg! posted:The big one is when data inheritance is implemented as a "base class" struct embedded in a "derived class" struct. Usually there will be a set of functions (of "virtual method" style) that take a pointer to the "base class" struct, but the function itself needs to access members of the "derived class". So you run into undefined behavior when you roll your own OOP in C, and you pick the non-obvious strategy of putting the base-class struct somewhere at the end (or do multiple inheritance I guess), and roll your own offsetof instead of using the one that comes with your implementation? That seems kinda managable, I dunno.
|
# ? Mar 4, 2013 06:55 |
|
I've been looking at this all night and just really need an extra set of eyes to help me out here. I'm doing infix to postfix conversion and my output for the postfix isn't showing operators. code:
|
# ? Mar 4, 2013 11:52 |
|
What exactly is output? That += may not be doing what you think it's doing. In general, learning how to use the debugger and stepping through your program really helps with figuring out this sort of thing.
|
# ? Mar 4, 2013 12:18 |
|
Jabor posted:What exactly is output? That += may not be doing what you think it's doing. It's a string variable but the += should still add additional characters to it right? I have it initialized as "" and it still takes the numerical values and stores them/displays them but not the operators of + - / or * I'll step through it after I wake up though edit; After taking a shower and not looking at it I realized I had the break for my isOperator function commented out for some reason and now it works perfectly fine I'm sorry Zomodok fucked around with this message at 15:01 on Mar 4, 2013 |
# ? Mar 4, 2013 12:21 |
|
How can I prevent a line of code from being optimized out no matter what type of build or platform? Like when I really need a breakpoint on a specific line in an optimized build, for debugging: code:
|
# ? Mar 5, 2013 01:44 |
|
Test a volatile variable or call a function that does.C++ code:
|
# ? Mar 5, 2013 02:09 |
|
baby puzzle posted:How can I prevent a line of code from being optimized out no matter what type of build or platform? Alternatively, generate the interrupt yourself. code:
|
# ? Mar 5, 2013 02:20 |
|
Alternatively, you can figure out how to set conditional breakpoints and sidestep the issue entirely.
|
# ? Mar 5, 2013 06:11 |
|
Conditional breakpoints won't necessarily work in an optimised build.
|
# ? Mar 5, 2013 10:56 |
b0lt posted:Alternatively, generate the interrupt yourself. This, but check if your compiler doesn't have an intrinsic function to generate the breakpoint. I know that MSVC does.
|
|
# ? Mar 5, 2013 11:02 |
|
nielsm posted:This, but check if your compiler doesn't have an intrinsic function to generate the breakpoint. I know that MSVC does.
|
# ? Mar 5, 2013 17:37 |
roomforthetuna posted:As I recall, both the intrinsic function and the asm in MSVC are frustratingly worse in the debugger than a debugger-added breakpoint - you have to take a couple of steps to get back to the context you're actually wanting to look at. I could be wrong about the asm but the breakpoint function was definitely completely balls. But at least you can be sure it won't be optimized out. You could set a breakpoint on the breakpoint and then jump over the int3 when it hits!
|
|
# ? Mar 5, 2013 17:39 |
|
I feel like the volatile variable is what I want. Our code builds/runs on a lot of different platforms so I want something that I am sure will work anywhere with minimal frustration. Thanks.
|
# ? Mar 5, 2013 17:53 |
|
I need to instantiate subclasses of some abstract class based on the value of a string, i.e. something equivalent toC++ code:
C++ code:
|
# ? Mar 5, 2013 19:56 |
|
I'm totally willing to defer to the advice of more knowledgeable people, but in the absence of anything from them I'd say "Anything that relies on complicated static initialization is something to really, really, really avoid." The standard doesn't guarantee any order of static initialization (as far as I know), and so you're forced to hack in your own determinism. There are a number of ways to do this but I've never seen one that doesn't suck. Personally, if this were my project, I'd probably forego the "automatic" registration and make new subclasses explicitly register themselves somewhere.
|
# ? Mar 5, 2013 21:16 |
|
Why are you passing that string s by non-const reference? You should go with the single createFoo function instead of a bunch of disparate static initializers. The code is less fragile that way, with no worries about somebody trying to create a foo during the static initialization phase. There's no real benefit to requiring that creators of new Foo subclasses remember to register their classes in some static initialization scheme, versus requiring that creators of new Foo subclasses remember to add their classes to some if/then/else list in foo.cpp. Besides, createFoo should really be the function in charge of deciding precisely how to create a Foo from a string, without much a care for what some random Foo subclass thinks about the matter.
|
# ? Mar 5, 2013 21:17 |
|
shrughes posted:You should go with the single createFoo function instead of a bunch of disparate static initializers. The code is less fragile that way, with no worries about somebody trying to create a foo during the static initialization phase. There's no real benefit to requiring that creators of new Foo subclasses remember to register their classes in some static initialization scheme, versus requiring that creators of new Foo subclasses remember to add their classes to some if/then/else list in foo.cpp. Besides, createFoo should really be the function in charge of deciding precisely how to create a Foo from a string, without much a care for what some random Foo subclass thinks about the matter. The benefits are encapsulation and flexibility.
|
# ? Mar 5, 2013 21:26 |
|
shrughes posted:Why are you passing that string s by non-const reference? Because I'm bad at C++ and I forgot to write const in the hastily-written example code block The specific use case is that I'm compiling a material description graph (read from Blender right now but the intent is to be generic) to a shading language (currently I can turn this into this, for instance) and it'd be practical for people to be able to write node descriptors and register them for compilation without needing to mess with the compiler itself. I guess I'll just have a method to register nodes and the author can worry about when to call it.
|
# ? Mar 5, 2013 21:36 |
|
roomforthetuna posted:Disagreed. If foo is a library or if classes are plugins He didn't say that in his first post. roomforthetuna posted:The benefits are encapsulation and flexibility. Nope, you don't get any more encapsulation, and you don't get any more flexibility in a non-plugin program. It's something to avoid unless you really need it. Edit: Actually, I haven't used dlls or anything plugin-based in like ten years but from what I remember with the way dlls work, even then you shouldn't use some spooky-action-at-a-distance static initialization stuff to register your classes -- you should communicate that registration stuff explicitly to the program. Edit II: The one time I would do this is when things are statically compiled and linked and the question of which source files are statically compiled and linked changes in some plugin-plugout like way. Edit III: The downside of the static initialization stuff in a statically linked program is fairly minimal compared to the amount of posting I'm doing about it -- assuming you do it correctly your code is a bit more brittle than it could be, but it's a self-contained brittleness. shrughes fucked around with this message at 22:28 on Mar 5, 2013 |
# ? Mar 5, 2013 22:18 |
|
I'm getting an error that I can't figure out (C89 code):C++ code:
I understand (I think) that enums and structs live in the same namespace, but I did a whole-project search and I don't use notice as the name of anything else anywhere. Any idea what's up? Compiler is ARM gcc 4.1 for reference.
|
# ? Mar 5, 2013 23:08 |
|
Otto Skorzeny posted:error: 'notice' defined as wrong kind of tag Are you using any libraries other than libc?
|
# ? Mar 5, 2013 23:20 |
|
Otto Skorzeny posted:I'm getting an error that I can't figure out (C89 code): Uh, this is C89? I don't think you can put a name like that after "notice". I think you have to do: C++ code:
|
# ? Mar 5, 2013 23:28 |
|
ExcessBLarg! posted:There a struct or union with the tag "notice" being included in the same file. Check the headers. Hrm. I'm using some vendor-supplied libraries that I have the source to, but full-text search including them didn't turn up any structs or unions with the name 'notice'. There was a struct in a header that had a field called 'notice', but it is my understanding that such things shouldn't collide with enum, struct or union tags (and temporarily removing it didn't elminiate the error). Renaming the enum did eliminate the error, however. I suppose I must have missed something when I was grepping.
|
# ? Mar 5, 2013 23:32 |
|
Suspicious Dish posted:Uh, this is C89? I don't think you can put a name like that after "notice". I think you have to do: You are wrong. The following is valid C89: C++ code:
quote:3.5.2.2 Enumeration specifiers Blotto Skorzany fucked around with this message at 23:43 on Mar 5, 2013 |
# ? Mar 5, 2013 23:35 |
|
Suspicious Dish posted:Uh, this is C89? I don't think you can put a name like that after "notice".
|
# ? Mar 5, 2013 23:43 |
|
I'm wrong. OK!
|
# ? Mar 6, 2013 00:58 |
|
Otto Skorzeny posted:I'm getting an error that I can't figure out (C89 code): Look at your code once it has been preprocessed. For gcc, that's gcc -E. This should give you a huge translation unit with all the definitions in-play at the point of your error.
|
# ? Mar 6, 2013 17:01 |
|
How workable is it to expose a C API that includes structures? I figure the choices are "assume it will always work," "assume it will never work," or something in-between. The specific thing I'm worried about is struct layout and portability. I'm imagining something like:C code:
|
# ? Mar 6, 2013 21:52 |
|
|
# ? Jun 8, 2024 09:27 |
|
I asked this a while ago and got distracted, so I'll ask more specifically. I am tasked to read in a data file of three columns (point) (value) (uncertainty) and feed it to something that's ported from Numerical Recipes in C to use GSL libraries that will do a Levenberg-Marqardt fit. I am reading the data file like this: code:
I am using this: code:
Lorentzian isn't really coded for what I'll need it to do yet, but as I'm reading this I want to be declaring it as: code:
code:
|
# ? Mar 6, 2013 22:06 |