#15918 - IGS - Wed Feb 04, 2004 9:59 am
Greetings all-
This is my first post on this forum, so I'll introduce myself before I get to the question. If you don't really care who I am, skip below the asteriks.
I'm a 20 year old anthropologist major from Mississippi, and in November of 2002 I stumbled onto gbajunkie's website, where I was introduced into the grand world of indie game development. I recruited a friend of mine whom I knew from my days as a CS major and we began development on a demo, which we hope to release shortly. It's a side-scrolling space shooter project that we are using primarily as a learning experience.
**********************************************************
We decided to follow the object-oriented paradigm for our first foray into GBA development, and we have been reasonably successful for a couple of console "GNU-B's" ?... but it has become quite obvious that most members of the GBA development community employ C as their language of choice. I have read through the forums and, sans a few vague hints that C might execute faster, I haven't noticed much explicit justification for this pattern. I am very curious- why do many programmers prefer C to C++? Any specific examples of situations where C executes more quickly, etc. will be greatly appreciated. As we wrap up our current project, we are preparing for a much longer second project, and we might contemplate using C instead of C++... given proper provocation, of course. Thanks to all who reply, and additional thanks to community members like Tepples, gbajunkie, sajimori, and poslundc who have already helped us through some newbie woes with their previous forum posts.
-IGS
#15920 - yaustar - Wed Feb 04, 2004 1:18 pm
There was a thread a couple of months back on this topic...cant remember when though...
_________________
[Blog] [Portfolio]
#15921 - poslundc - Wed Feb 04, 2004 2:47 pm
OK, here's one of my beefs with C++ on the GBA.
It forces ("strongly encourages") you to use a certain paradigm, ie. the object-oriented model. Problem is, computers aren't inherently object-oriented. They are strictly procedural.
This is not a problem 90% of the time, but when you're programming for a console like the GBA where often every cycle counts, you want to remain very close to the hardware representation of your code, and it does not help to wedge a paradigm in between the two.
It's easy to fall into a sort of a trap for newbie GBA programmers where if you follow the Pern tutorials or whatnot you can actually get quite far while being oblivious to many things that the compiler and the CPU actually do, and it comes back to bite you in the ass later on. This happened to me, and I was an experienced C programmer when I first started out. I think it could be worse for C++ programmers, because there is another level of obscurity between your code and what the compiler does. Things like polymorphism, templates, etc. can cause a lot of problems if you aren't aware of precisely what the compiler is doing.
The fact of the matter is, there's nothing you can do in C++ you can't do in regular C, so long as you maintain the proper coding discipline. All of my work is rigorously broken up into modules and I control what parts are accessible to other modules. By keeping the onus on myself, I find it actually keeps things clearer for me than if I were using OO.
There is a case for C++ as well. It was first invented not because C couldn't do the job, but because it was too easy to use C in a non-structured way. I suppose if you're working in teams where you can't assure the competence of everyone, it can help to have something like C++ to enforce a common design methodology. Also, nowadays g++ should be comparable in efficiency to gcc, so if you really like the OO paradigm then you shouldn't be losing too much by using it.
One final reason to stick to C, though, is that it's what most people in this forum use, which means we will be able to be a lot more helpful in troubleshooting your stuff. :) (Not trying to bully you into going with the crowd or anything; it's just that I and many others will skip over posts that require knowledge of a certain library, language, etc. that we aren't readily familiar with.)
Dan.
#15928 - col - Wed Feb 04, 2004 5:30 pm
As you can see from the results in this poll from the yahoo mailing list, plenty of gba developers use c++
http://groups.yahoo.com/group/gbadev/surveys?id=937034
Assembly 6 7.32%
C 48 58.54%
C++ 28 34.15%
Others? 0 0.00%
If you are a proficient c++ programmer - use c++.
If not, use c until you have the time to learn how to use c++ properly.
poslundc wrote: |
It forces ("strongly encourages") you to use a certain paradigm |
this statement has far more truth when applied to c than c++!
poslundc wrote: |
This is not a problem 90% of the time, but when you're programming for a console like the GBA where often every cycle counts, you want to remain very close to the hardware representation of your code, and it does not help to wedge a paradigm in between the two. |
If if every cycle really does count then there is no question - you should be coding in assembly language!
Otherwise, c++ will give you the same performance that c does
poslundc wrote: |
...and it comes back to bite you in the ass later on. This happened to me, and I was an experienced C programmer when I first started out. I think it could be worse for C++ programmers... |
it sounds like you don't really know c++ well enough to compare it to c ?
poslundc wrote: |
because there is another level of obscurity between your code and what the compiler does... |
If there is obscurity between your code and what the compiler does its usually caused by badly designed code or ignorance or both ;)
However, if there is another level of abstraction that is often a good thing! Mind you it's important to understand any performance implications that the particular abstractions you are using might have.
poslundc wrote: |
The fact of the matter is, there's nothing you can do in C++ you can't do in regular C |
Not true... eg. how do you do template meta-programming in c ? How can you get the level of strong type checking that c++ has in c ?...
A more accurate statement would have been, "there's nothing you can do in c you can't do in regular c++"
cheers
Col
#15930 - Miked0801 - Wed Feb 04, 2004 6:19 pm
Ok, I'll give it a go.
There are 2 reasons that I code in C.
1. (main reason) Until recently, all C++ compilers I had run across on the various consoles I've programmed for were buggy and inefficient (if they ran at all). Therefore my coding efficiency in C is much higher than C++. If I had a job where I was forced to use C++ for a month or two, I'd probably use C++ on the GBA just because that is where I am most efficient.
2. There is a (possibly false) believe that in general C will translate to smaller/faster code than C++. It's easy to say that if speed matters, code in assembly, but even when speed doesn't matter as much, it's still nice to have fast code. Truth is, after looking at the output for our C compiler, I'm not too sure that it can be much worse than C++ in terms of efficiency - bleh.
Mike
#15932 - poslundc - Wed Feb 04, 2004 6:31 pm
col wrote: |
poslundc wrote: | It forces ("strongly encourages") you to use a certain paradigm |
this statement has far more truth when applied to c than c++! |
I don't see how. C is a simple procedural language. C++ is a procedural language but with an object-oriented layer on top of it.
Quote: |
If if every cycle really does count then there is no question - you should be coding in assembly language!
Otherwise, c++ will give you the same performance that c does |
That may very well be the case with current compilers. Although if you rigorously apply the rules of information-hiding you will generate much bulkier code (even if it is better engineered for having done so). You need to think an awful lot more about how the compiler is translating your OO stuff to procedural code in order to write efficiently.
Quote: |
it sounds like you don't really know c++ well enough to compare it to c ? |
I've done more than my fair share of C++ programming, thank-you-very-much.
poslundc wrote: |
If there is obscurity between your code and what the compiler does its usually caused by badly designed code or ignorance or both ;)
However, if there is another level of abstraction that is often a good thing! Mind you it's important to understand any performance implications that the particular abstractions you are using might have. |
Well, that's precisely my point. C++ is fine so long as you know the costs of its features. Many newbie GBA programmers are very unaware of how things look to the compiler, though.
Quote: |
poslundc wrote: | The fact of the matter is, there's nothing you can do in C++ you can't do in regular C |
Not true... eg. how do you do template meta-programming in c ? How can you get the level of strong type checking that c++ has in c ?... |
These features don't let you "do" anything that you can't do in C. They just change the way you go about coding it. But the more you let the compiler do for you (such as with templates), the further you are abstracted from the machine's code. Which is fine to an extent, or if you know what you're doing, but then you have to be content with keeping track of those rules in order to keep your code efficient. For me, it's easier to just code it in C.
Quote: |
A more accurate statement would have been, "there's nothing you can do in c you can't do in regular c++" |
That should be obvious, seeing as C++ is a superset of C. I'm sure I don't need to tell you that the early C++ compilers simply translated from C++ to C. The point I was making is that just because C++ has more features doesn't mean it does the job any better.
At the end of the day, the tradeoff is getting the features of OO in exchange for an additional layer of abstraction. In terms of performance, the cost is probably negligible-to-nonexistant 99% of the time (at least it should be nowadays), so the only consideration is whether or not the additional layer of abstraction is a good thing. If you're keen on the OO paradigm, then sure, go for it (or better still go for Objective C :), but if not then there's really no point to it, since the paradigm is just another layer between you and the machine code.
Dan.
#15934 - col - Wed Feb 04, 2004 7:52 pm
poslundc wrote: |
col wrote: | poslundc wrote: | It forces ("strongly encourages") you to use a certain paradigm |
this statement has far more truth when applied to c than c++! |
I don't see how. C is a simple procedural language. C++ is a procedural language but with an object-oriented layer on top of it.
|
C is a simple procedural language - it 'strongly encourages' you to use he procedural paradigm.
C++ does not have an "an object-oriented layer on top of it". It has -among many other things - built in language facilities that make it much easier to use the object oriented paradigm if you so wish.
poslundc wrote: |
...if you rigorously apply the rules of information-hiding you will generate much bulkier code (even if it is better engineered for having done so).
|
If you apply the rules of information-hiding carefully and pragmatically, you can get most of the benifits with additional no size or performance cost.
You really have to start getting into stuff like 'pimpl' before you take a (small) performance hit.
poslundc wrote: |
You need to think an awful lot more about how the compiler is translating your OO stuff to procedural code in order to write efficiently.
|
To write efficient code in any language, you need to understand what is happening 'under the hood'. One of the biggest problems with c++ is that it is so big that it takes a lot of study and experience to accumulate this knowledge and to get the most out of the language.
Luckily, you only need to have this knowledge for the parts of the language that you are using. So if you're not using RTTI, you can switch it off and forget about it - same goes for Exceptions, Templates, STL etc...
poslundc wrote: |
poslundc wrote: | If there is obscurity between your code and what the compiler does its usually caused by badly designed code or ignorance or both ;)
However, if there is another level of abstraction that is often a good thing! Mind you it's important to understand any performance implications that the particular abstractions you are using might have. |
Well, that's precisely my point. C++ is fine so long as you know the costs of its features. Many newbie GBA programmers are very unaware of how things look to the compiler, though.
|
I though we were discussing the comparative merits of c and c++ as languages for gba programming - not which is easiest for a beginner to learn?
poslundc wrote: |
Quote: | poslundc wrote: | The fact of the matter is, there's nothing you can do in C++ you can't do in regular C |
Not true... eg. how do you do template meta-programming in c ? How can you get the level of strong type checking that c++ has in c ?... |
These features don't let you "do" anything that you can't do in C. They just change the way you go about coding it.
|
my point exactly! c++ offers a greater variety of programming paradigms - it gives you the freedom to "just change the way you go about coding it". you can do it the procedural 'c' way using c++ or you can apply polymorphism, or template meta-programming... or even better, you can mix 'n' match.
poslundc wrote: |
But the more you let the compiler do for you (such as with templates), the further you are abstracted from the machine's code. Which is fine to an extent, or if you know what you're doing, but then you have to be content with keeping track of those rules in order to keep your code efficient. For me, it's easier to just code it in C.
|
...and the further you are abstracted from the machines code, the easier it becomes to build and maintain larger more complex and more powerful systems of software. Nice thing about c++ is that it lets you balance the trade-offs to match the scale of the project
poslundc wrote: |
Quote: | A more accurate statement would have been, "there's nothing you can do in c you can't do in regular c++" |
That should be obvious, seeing as C++ is a superset of C. I'm sure I don't need to tell you that the early C++ compilers simply translated from C++ to C. The point I was making is that just because C++ has more features doesn't mean it does the job any better.
|
c++ dosn't 'do a job' it provides a toolset for us programmers to do a job. for better or worse, c++ provides a larger more flexible toolset than most other languages.. this can be 'just what the doctor ordered', or 'just enough rope' - it really depends on the programmer
cheers,
Col
#15935 - sajiimori - Wed Feb 04, 2004 8:02 pm
I'd like to echo col in every way except this one:
Quote: |
If you are a proficient c++ programmer - use c++.
If not, use c until you have the time to learn how to use c++ properly.
|
I would add to the second sentence: "and you feel that C++ will help you do better work." If you don't see how it could help you, chances are it won't.
#15937 - sajiimori - Wed Feb 04, 2004 8:08 pm
Quote: |
c++ provides a larger more flexible toolset than most other languages
|
Careful...do you know most other languages? Try Lisp sometime. A small dialect like Scheme is orders of magnitude simpler than C++, yet far more flexible. (You can extend C++ with new data structures, but can you extend it with new code structures?)
Edit: on second thought, 'most languages' is too vague to make my comment interesting.
#15941 - poslundc - Wed Feb 04, 2004 8:44 pm
col wrote: |
C is a simple procedural language - it 'strongly encourages' you to use he procedural paradigm. |
Procedural coding is more than a paradigm; it's how the vast majority of digital programmable computers actually work. So if it's a paradigm for anything it's a paradigm for the hardware. I am not aware of any hardware that adopts the OO paradigm, certainly nothing mainstream.
Quote: |
If you apply the rules of information-hiding carefully and pragmatically, you can get most of the benifits with additional no size or performance cost.
You really have to start getting into stuff like 'pimpl' before you take a (small) performance hit. |
"Pragmatically" is the key word. Information hiding and modularization is designed to produce better structured (and as you observe, more maintainable, as well as testable and verifiable) code. Not fast or even efficient code. The two are not necessarily mutually exclusive, but OO principles naturally favour the former over the latter.
If I'm to call an access routine just to get or set the value of a private variable, and that routine then has to perform bounds tests on the value I submit, and then generate an exception if I'm out of bounds, well, that's the way it should be from an engineering standpoint, but it may not be the ideal when I'm trying to make Pong run fast. :)
You can, of course, do all that with C, and you don't necessarily have to do all of that with C++. My only point is that C isn't predisposed to doing things a certain way. C++ is, however.
Quote: |
I though we were discussing the comparative merits of c and c++ as languages for gba programming - not which is easiest for a beginner to learn? |
I suppose my point is that as you start to understand how the compiler interprets your code to the hardware, things get more-and-more procedural and less-and-less object-oriented. Learning curve aside, plain C code is just closer to the underlying assembly in terms of structure than C++ code is. This isn't a performance argument or anything, just an observation on levels of abstraction. As you've pointed out, increasing levels of abstraction can be a very good thing, but it's not always desirable when working on a low-level system.
Quote: |
my point exactly! c++ offers a greater variety of programming paradigms - it gives you the freedom to "just change the way you go about coding it". you can do it the procedural 'c' way using c++ or you can apply polymorphism, or template meta-programming... or even better, you can mix 'n' match. |
OK, but you can do object-oriented programming in C if you want to; you just have to take a bit more care in order to implement it. I've seen plenty of excellent OO APIs in C that implement features like polymorphism and whatnot. Why weren't they written in C++ instead? Well, for one, there was no reason to do so; C was sufficient.
Quote: |
...and the further you are abstracted from the machines code, the easier it becomes to build and maintain larger more complex and more powerful systems of software. Nice thing about c++ is that it lets you balance the trade-offs to match the scale of the project |
Well-structured, modular C code is just as buildable and maintainable as any C++ code. OTOH, poorly-written C++ code is just as spaghetti and problematic as any C code. It's up to the discipline of the programmer, and many C++ programmers do not realize that just because they are using OO it doesn't make their programs well-designed or modularized. C programmers, on the other hand, typically find out a lot quicker if they're no good at it. :)
Whether it's a good thing that C makes you take modularization into your own hands is a matter of opinion; the arguments for either side should be self-evident.
Quote: |
c++ dosn't 'do a job' it provides a toolset for us programmers to do a job. for better or worse, c++ provides a larger more flexible toolset than most other languages.. this can be 'just what the doctor ordered', or 'just enough rope' - it really depends on the programmer |
On that, we agree.
Dan.
#15942 - tepples - Wed Feb 04, 2004 9:00 pm
col wrote: |
How can you get the level of strong type checking that c++ has in c ? |
True, C++ has a much more powerful template preprocessor, but for type checking in C, try gcc -Wall -Werror
Quote: |
the further you are abstracted from the machines code, the easier it becomes to build and maintain larger more complex and more powerful systems |
The more abstraction you use, the easier it becomes to forget "what is happening 'under the hood'" as you put it and to make design errors that result in bigger footprint and longer execution.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#15943 - sajiimori - Wed Feb 04, 2004 9:42 pm
Quote: |
Procedural coding is more than a paradigm; it's how the vast majority of digital programmable computers actually work. So if it's a paradigm for anything it's a paradigm for the hardware. I am not aware of any hardware that adopts the OO paradigm, certainly nothing mainstream.
|
I hate to break it to you, but OO is not an alternative to procedural programming. C++, Java, C#, etc are all very procedural, meaning code is mostly divided into procedures that are usually run for their side-effects (rather than their return values).
Quote: |
Information hiding and modularization is designed to produce better structured (and as you observe, more maintainable, as well as testable and verifiable) code. Not fast or even efficient code.
|
Given the choice between a language that allows me to use the style I feel is appropriate versus a language that forces me to think about low-level details all the time, I would choose the flexible one every time.
Quote: |
If I'm to call an access routine just to get or set the value of a private variable, and that routine then has to perform bounds tests on the value I submit, and then generate an exception if I'm out of bounds, well, that's the way it should be from an engineering standpoint, but it may not be the ideal when I'm trying to make Pong run fast. :)
|
Engineering is about making the right trade-offs to meet certain requirements. Since speed is sometimes a requirement, it may override other concerns. I want to be able to choose what my priorities are for each situation, at a very fine resolution. My priorities could change drastically when going from the innermost loop of an algorithm to the next one out.
Quote: |
My only point is that C isn't predisposed to doing things a certain way. C++ is, however.
|
And if I make a new language that's exactly like C++ except it supports closures, would you say it's predisposed to doing things using closures?
I agree with col that given 2 languages where one is a subset of the other, the smaller language will necessarily be more restrictive. (The most significant way that C is not a subset of C++ is also the only way I can think of that it is less restrictive: it doesn't force the use of prototypes.)
Quote: |
Learning curve aside, plain C code is just closer to the underlying assembly in terms of structure than C++ code is.
|
Depends on the code, obviously. If you want to compare apples to apples, the C++ code will tend to look almost exactly like the C code.
Quote: |
As you've pointed out, increasing levels of abstraction can be a very good thing, but it's not always desirable when working on a low-level system.
|
If it's sometimes desirable, why would you want to deny yourself the option?
Quote: |
OK, but you can do object-oriented programming in C if you want to; you just have to take a bit more care in order to implement it.
|
You can also do it in assembly, or Befunge. You just have to re-implement it every time you want to use it, with all the guts exposed.
Quote: |
Whether it's a good thing that C makes you take modularization into your own hands is a matter of opinion; the arguments for either side should be self-evident.
|
I can't think of any good arguments for having to prefix all global function names with an abbreviation of the module name, to avoid conflicts.
#15947 - poslundc - Wed Feb 04, 2004 10:49 pm
sajiimori wrote: |
Quote: |
Procedural coding is more than a paradigm; it's how the vast majority of digital programmable computers actually work. So if it's a paradigm for anything it's a paradigm for the hardware. I am not aware of any hardware that adopts the OO paradigm, certainly nothing mainstream.
|
I hate to break it to you, but OO is not an alternative to procedural programming. C++, Java, C#, etc are all very procedural, meaning code is mostly divided into procedures that are usually run for their side-effects (rather than their return values). |
I've already made this distinction in earlier posts. C++ is a procedural language, but OOP is not inherently procedural, and tries to break free of the procedural way of thinking.
Quote: |
Quote: |
Information hiding and modularization is designed to produce better structured (and as you observe, more maintainable, as well as testable and verifiable) code. Not fast or even efficient code.
|
Given the choice between a language that allows me to use the style I feel is appropriate versus a language that forces me to think about low-level details all the time, I would choose the flexible one every time.
|
That's fine, so long as you're happy with that style. Not everyone likes OO, or at least not the C++ implementation of it.
Quote: |
Quote: |
My only point is that C isn't predisposed to doing things a certain way. C++ is, however.
|
And if I make a new language that's exactly like C++ except it supports closures, would you say it's predisposed to doing things using closures? |
Well, let's get one thing straight: if you're just going to run a regular C program in your C++ compiler, then the discussion is moot. When most people talk about using C++ they are talking about using it for OOP.
Quote: |
I agree with col that given 2 languages where one is a subset of the other, the smaller language will necessarily be more restrictive. (The most significant way that C is not a subset of C++ is also the only way I can think of that it is less restrictive: it doesn't force the use of prototypes.) |
It's not more restrictive when both languages can do the same thing. Heck, I don't even need while loops, so long as I have the goto statement. While loops enhance the language, but lack of them wouldn't make C any more restrictive.
And before you say it: yes, C++ enhances the C language in the same way while loops enhance gotos, but OOP brings in a level of abstraction that is very different from the abstraction of a while loop.
Quote: |
Quote: |
Learning curve aside, plain C code is just closer to the underlying assembly in terms of structure than C++ code is.
|
Depends on the code, obviously. If you want to compare apples to apples, the C++ code will tend to look almost exactly like the C code. |
Again, the argument only has relevance in context that C++ is generally used for its OOP features.
Quote: |
Quote: | As you've pointed out, increasing levels of abstraction can be a very good thing, but it's not always desirable when working on a low-level system. |
If it's sometimes desirable, why would you want to deny yourself the option? |
I don't see how I'm denying myself the option by using C. I can make things abstract to all kinds of levels in that language.
Quote: |
Quote: |
OK, but you can do object-oriented programming in C if you want to; you just have to take a bit more care in order to implement it.
|
You can also do it in assembly, or Befunge. You just have to re-implement it every time you want to use it, with all the guts exposed. |
So if you're keen on OO (and like the C++ implementation), then C++ is an obvious choice. A program does not need to be OO in order to be well-structured or modular, though.
Quote: |
I can't think of any good arguments for having to prefix all global function names with an abbreviation of the module name, to avoid conflicts. |
How about that it keeps the context of your function calls clear and visible at all times?
Dan.
#15950 - sajiimori - Wed Feb 04, 2004 11:26 pm
Quote: |
It's not more restrictive when both languages can do the same thing.
|
...as long as you don't mind having to re-implement it every time you use it.
Quote: |
And before you say it: yes, C++ enhances the C language in the same way while loops enhance gotos, but OOP brings in a level of abstraction that is very different from the abstraction of a while loop.
|
Yeah, they're abstractions at different levels. 'While' loops are at the statement/expression level, and classes and such are at the procedure/application level. How does that mean my argument applies to 'while' loops but not OO features?
Quote: |
Again, the argument only has relevance in context that C++ is generally used for its OOP features.
|
Are you arguing against C++, or OOP? If you're arguing against C++, you shouldn't fall back on statements like this one. If you're arguing against OOP, you shouldn't fall back on "well, C can do OOP too."
Quote: |
I don't see how I'm denying myself the option by using C. I can make things abstract to all kinds of levels in that language.
|
I'm talking about the specific abstractions that C++ lets you use that C does not let you use. If you have to re-implement a feature every time you use it, that means your language does not allow you to abstract it. "All kinds of levels" is an exaggeration.
Quote: |
How about that it keeps the context of your function calls clear and visible at all times?
|
I think it's just a bunch of clutter that's required to work around the stupidity of the compiler.
#15952 - IGS - Wed Feb 04, 2004 11:30 pm
Wow. There have been some really good posts in this topic. I feel as though I understand why different programmers around this community have chosen the languages they have. I suppose a more accurate title for this thread would have been "Pros and Cons of the OO Paradigm." Allow me to summarize what has been posted so far (please correct me if I misstate or misrepresent a point):
1) Neither language is inherently faster than the other... a difference
in speed is only caused by the ways in which the languages are used.
2) Neither language is necessarily more organized (although I am
tempted to agree with the assessment that C++ lends itself to
organization more so than C)
3) A side effect of the higher level of abstraction provided by an OO
paradigm is that it is easier to lose sight of the actual instructions
executed on hardware for each set of command or statements... this
is a good thing in a high resource environment, as the programmer can
wield large amounts of code without worrying about details, but in a
limited resource environment this can lead to inefficient programming.
So the question is really a matter of matching the correct ideology to how much performance any particular game requires from the GBA, correct? If a low-demand game is being produced, an OO paradigm would be most useful for the programmer's sometimes fragile mental state (well my mind is anyway), but a high-demand game might be better implemented with an eye to procedure reduction rather than the OOP. Is this a fair statement? If so, the question becomes-
"What is high demand, and what is low demand?"
Any ideas? Or if I've misstated something, please feel free to correct me. This has been very informative so far!
BTW, poslundc- I checked out your environment demo (with the hero from Secret of Mana) on your site... It's quite nice!
-IGS
#15953 - sajiimori - Wed Feb 04, 2004 11:44 pm
Quote: |
1) Neither language is inherently faster than the other... a difference
in speed is only caused by the ways in which the languages are used.
|
Yes. Long ago, C++ compilers generated slower object code given the same source because of the exception-handling mechanisms they used. But now, there's no difference.
Quote: |
2) Neither language is necessarily more organized (although I am
tempted to agree with the assessment that C++ lends itself to
organization more so than C)
|
C++ offers a few extra tools, but it's still up to the programmer to use them well. If the programmer doesn't feel restricted with C, chances are he wouldn't use C++ features in an effective way.
Quote: |
3) A side effect of the higher level of abstraction provided by an OO
paradigm is that it is easier to lose sight of the actual instructions
executed on hardware for each set of command or statements... this
is a good thing in a high resource environment, as the programmer can
wield large amounts of code without worrying about details, but in a
limited resource environment this can lead to inefficient programming.
|
Absolutely. But given the 80/20 rule, I think good code design should come first.
Quote: |
So the question is really a matter of matching the correct ideology to how much performance any particular game requires from the GBA, correct? If a low-demand game is being produced, an OO paradigm would be most useful for the programmer's sometimes fragile mental state (well my mind is anyway), but a high-demand game might be better implemented with an eye to procedure reduction rather than the OOP.
|
I'd suggest not trying to conform to any particular ideology. Just be aware of your entire toolset, and apply the ones that make your code the simplest. Optimize last, and use a profiler.
I read an article about the Crash Bandicoot games for PS1. They spent an enormous amount of effort optimizing the engine, but 80-90% of the game was written in a Lisp-like scripting language. Even when speed is a very high priority, most of the code should be written with simplicity and elegance in mind.
#15955 - col - Wed Feb 04, 2004 11:47 pm
poslundc wrote: |
col wrote: | C is a simple procedural language - it 'strongly encourages' you to use he procedural paradigm. |
Procedural coding is more than a paradigm; it's how the vast majority of digital programmable computers actually work. So if it's a paradigm for anything it's a paradigm for the hardware. I am not aware of any hardware that adopts the OO paradigm, certainly nothing mainstream.
|
Look at the common flow control constructs in c such as for loops, if then else, do...while, switch statements, function calls - these are not supported directly in the majority of modern processors - they are all abstractions
Unless you pretty much exclusively use goto, you are not likely to be using code that works the same way your computer does!
poslundc wrote: |
Quote: | If you apply the rules of information-hiding carefully and pragmatically, you can get most of the benifits with additional no size or performance cost.
You really have to start getting into stuff like 'pimpl' before you take a (small) performance hit. |
"Pragmatically" is the key word. Information hiding and modularization is designed to produce better structured (and as you observe, more maintainable, as well as testable and verifiable) code. Not fast or even efficient code. The two are not necessarily mutually exclusive, but OO principles naturally favour the former over the latter.
If I'm to call an access routine just to get or set the value of a private variable, and that routine then has to perform bounds tests on the value I submit, and then generate an exception if I'm out of bounds, well, that's the way it should be from an engineering standpoint, but it may not be the ideal when I'm trying to make Pong run fast. :)
|
The example you give is misleading - the bounds checking is a red herring - you can do that in c or c++(with or without encapsulation) it's a design decision - nothing to do with language specifics. Exceptions are optional.
The accessor method on the other hand can provide encapsulation for your data, and in the vast majority of cases will be completely optimised away by the compiler.
poslundc wrote: |
You can, of course, do all that with C, and you don't necessarily have to do all of that with C++. My only point is that C isn't predisposed to doing things a certain way. C++ is, however.
|
c++ is in no more predisposed to doing things a certain way than c - quite the opposite.
poslundc wrote: |
Quote: | I though we were discussing the comparative merits of c and c++ as languages for gba programming - not which is easiest for a beginner to learn? |
I suppose my point is that as you start to understand how the compiler interprets your code to the hardware, things get more-and-more procedural and less-and-less object-oriented.
|
How so?
poslundc wrote: |
Quote: | my point exactly! c++ offers a greater variety of programming paradigms - it gives you the freedom to "just change the way you go about coding it". you can do it the procedural 'c' way using c++ or you can apply polymorphism, or template meta-programming... or even better, you can mix 'n' match. |
OK, but you can do object-oriented programming in C if you want to; you just have to take a bit more care in order to implement it. I've seen plenty of excellent OO APIs in C that implement features like polymorphism and whatnot. Why weren't they written in C++ instead? Well, for one, there was no reason to do so; C was sufficient.
|
so you are working on a game - you get offered a deal - wow superb:). Damn, they only give you 2 months to finish the game :(. Yay they give you loads of cash to hire extra staff :).
(a) you coded the whole thing up using a non standard polymorphic c API.
(b) you coded it all in standard c++
at this point if I had done (a), I would be wishing I had done (b) ;)
cheers
Col
#15956 - poslundc - Wed Feb 04, 2004 11:53 pm
Quote: |
Quote: |
And before you say it: yes, C++ enhances the C language in the same way while loops enhance gotos, but OOP brings in a level of abstraction that is very different from the abstraction of a while loop.
|
Yeah, they're abstractions at different levels. 'While' loops are at the statement/expression level, and classes and such are at the procedure/application level. How does that mean my argument applies to 'while' loops but not OO features? |
It doesn't. My whole point is that if you got rid of while loops and only used gotos, it wouldn't make C any more restrictive. What it would do is make it less structured. But that's a different matter.
Quote: |
Quote: |
Again, the argument only has relevance in context that C++ is generally used for its OOP features.
|
Are you arguing against C++, or OOP? If you're arguing against C++, you shouldn't fall back on statements like this one. If you're arguing against OOP, you shouldn't fall back on "well, C can do OOP too." |
I'm primarily arguing against OOP, as implemented in C++, which is what C++ is generally used for. If you're not going to use OOP in C++, then for all intents and purposes you are just programming in C anyway.
The statement about C being able to also do OOP is in reference to the notion that C is somehow more limited in functionality than C++. I am not attempting to defend or condemn OOP by saying so. There's more than one leaf in the pile here.
Quote: |
Quote: |
I don't see how I'm denying myself the option by using C. I can make things abstract to all kinds of levels in that language.
|
I'm talking about the specific abstractions that C++ lets you use that C does not let you use. If you have to re-implement a feature every time you use it, that means your language does not allow you to abstract it. "All kinds of levels" is an exaggeration. |
Repetition doesn't preclude abstractism. I don't know where that notion comes from. I can code a module in assembler and if I don't need to worry about its inner workings in order to use it, then it will be abstract. It is possible to make very significant, useful abstractions in C with very little effort. The unstructured form of C just means you need to know how to do it yourself, vs. C++ where you've got OOP as a tool to do so.
Quote: |
Quote: |
How about that it keeps the context of your function calls clear and visible at all times?
|
I think it's just a bunch of clutter that's required to work around the stupidity of the compiler. |
Well, then I suppose C isn't for you. :D How do you feel about namespaces in Java?
Dan.
#15960 - poslundc - Thu Feb 05, 2004 12:19 am
col wrote: |
poslundc wrote: | Procedural coding is more than a paradigm; it's how the vast majority of digital programmable computers actually work. So if it's a paradigm for anything it's a paradigm for the hardware. I am not aware of any hardware that adopts the OO paradigm, certainly nothing mainstream. |
Look at the common flow control constructs in c such as for loops, if then else, do...while, switch statements, function calls - these are not supported directly in the majority of modern processors - they are all abstractions
Unless you pretty much exclusively use goto, you are not likely to be using code that works the same way your computer does! |
Of course it's an abstraction. That's not the point. The point is that it doesn't abstract away from the procedural nature of the computer, the way things like functional languages and OOP do.
(I'll sidebar here, in case my meaning is getting lost through the pile of messages, I am not fundamentally opposed to OOP, or functional languages, or anything like that! This all resides within the context of this discussion, which is C vs. C++ for GBA programming.)
Quote: |
The example you give is misleading - the bounds checking is a red herring - you can do that in c or c++(with or without encapsulation) it's a design decision - nothing to do with language specifics. Exceptions are optional.
The accessor method on the other hand can provide encapsulation for your data, and in the vast majority of cases will be completely optimised away by the compiler. |
Please understand, I'm not saying you're forced to do things a certain way in either language. I'm saying that OOP - and by extension of that, C++ - lends itself to a certain style of programming.
Quote: |
c++ is in no more predisposed to doing things a certain way than c - quite the opposite. |
How often does someone tell you they are using C++ without also implying that they are using OOP by doing so?
Quote: |
Quote: | I suppose my point is that as you start to understand how the compiler interprets your code to the hardware, things get more-and-more procedural and less-and-less object-oriented.
|
How so? |
Because digital computers are based on the procedural paradigm: sets of instructions executed in a linear sequence. OOP is based on the idea of collections of state-based objects with messages passed back and forth between them. You could probably have an OOP computer of sorts - simple finite-state machines can behave very much like objects, I suppose (such as the LCD display of a clock) - but computers are designed fundamentally from a procedural viewpoint.
Quote: |
so you are working on a game - you get offered a deal - wow superb:). Damn, they only give you 2 months to finish the game :(. Yay they give you loads of cash to hire extra staff :).
(a) you coded the whole thing up using a non standard polymorphic c API.
(b) you coded it all in standard c++
at this point if I had done (a), I would be wishing I had done (b) ;) |
A or B will make very little difference if your underlying modularization is poor. None of the features of C++ will save you from that. If your underlying modularization is well-designed, then you should be able to use either one.
The danger with C++ is that many programmers think that because they make their program OO that it will automatically be well-designed.
Dan.
#15961 - sajiimori - Thu Feb 05, 2004 12:21 am
Quote: |
It doesn't. My whole point is that if you got rid of while loops and only used gotos, it wouldn't make C any more restrictive. What it would do is make it less structured. But that's a different matter.
|
Fine. s/restrictive/less structured/, so C is "less structured" than C++ because it doesn't support as many abstractions. (I think "restrictive" is a better choice of words, because "structured" is already tied to "structured programming".)
Quote: |
If you're not going to use OOP in C++, then for all intents and purposes you are just programming in C anyway.
|
Disagree. But I think it's pointless to argue about it unless we agree on a definition of "object-oriented programming", which nobody really ever does.
Quote: |
Repetition doesn't preclude abstractism. I don't know where that notion comes from.
|
"Repetition doesn't preclude abstractism." <-- I don't know where that notion comes from. ;-)
My definition of abstraction means encapsulating the repetitive parts, to remove the repitition. What's yours mean?
Quote: |
I can code a module in assembler and if I don't need to worry about its inner workings in order to use it, then it will be abstract.
|
That's right, but you can only abstract certain things. For instance, you can abstract a factorial function, but you couldn't abstract the process of defining functions, or doing 'while' loops, or defining reusable data structures. Every time you want to do those things, you have to repeat the implementation.
Quote: |
The unstructured form of C just means you need to know how to do it yourself, vs. C++ where you've got OOP as a tool to do so.
|
Yeah, you have to know how to do it, and also be willing to repeat the 'how' part every time you do it, because you can't abstract the 'how' part away. To use method inheritance, you always have to make a struct with a pointer to a struct that has pointers to functions, but you can't encapsulate that process and put the details into C functions (because C functions can't write structs), or macros (because macros are too stupid).
Quote: |
How do you feel about namespaces in Java?
|
Java sucks. =) But the namespace/package idea is a no-brainer (it's much older than Java). It's a hassle-free way to prevent name clashes.
#15962 - sajiimori - Thu Feb 05, 2004 12:27 am
Quote: |
I'm saying that OOP - and by extension of that, C++ - lends itself to a certain style of programming.
|
But why argue against a language (for GBA or otherwise) because it lends itself to more styles of programming? How could that possibly be a loss? (My favorite language is Lisp. It lends itself to every style of programming currently known, and all known styles are a subset of Lisp.)
Quote: |
How often does someone tell you they are using C++ without also implying that they are using OOP by doing so?
|
A cultural issue.
Quote: |
The danger with C++ is that many programmers think that because they make their program OO that it will automatically be well-designed.
|
Not the fault of the language.
#15963 - poslundc - Thu Feb 05, 2004 12:37 am
IGS wrote: |
1) Neither language is inherently faster than the other... a difference
in speed is only caused by the ways in which the languages are used. |
This is pretty much true, as far as I am aware, although historically C++ code was slower than C code.
Quote: |
2) Neither language is necessarily more organized (although I am
tempted to agree with the assessment that C++ lends itself to
organization more so than C) |
The tricky bit here is that C++ lends itself to a certain kind of organization. Which is fine for many people, but it can also be a panacea for those who do not know any better.
C is inherently unorganized, but can be as organized as you want it to be.
C++ asks you to be organized in a certain way, conforming to the OO technique.
Quote: |
3) A side effect of the higher level of abstraction provided by an OO
paradigm is that it is easier to lose sight of the actual instructions
executed on hardware for each set of command or statements... this
is a good thing in a high resource environment, as the programmer can
wield large amounts of code without worrying about details, but in a
limited resource environment this can lead to inefficient programming. |
This is true from a technical aspect, but I think more to the point is the way the programmer thinks. If you are thinking in terms of objects and methods (not necessarily a bad thing!) it means your thinking is not as analogous to what the processor is doing as if you are thinking in terms of loops and functions.
Quote: |
So the question is really a matter of matching the correct ideology to how much performance any particular game requires from the GBA, correct? If a low-demand game is being produced, an OO paradigm would be most useful for the programmer's sometimes fragile mental state (well my mind is anyway), but a high-demand game might be better implemented with an eye to procedure reduction rather than the OOP. Is this a fair statement? If so, the question becomes-
"What is high demand, and what is low demand?" |
See, here's my beef with OOP. It's a panacea: many programmers think that if they just break down their program into objects they no longer have to worry about proper design. OOP is simply a technology: a way of doing things. It can be useful, but you need to know what you're using it for and why. Otherwise you're just jamming a square peg into what could be a round hole. One of the most illuminating comments on the matter I've heard in this forum was actually from sajimori was in another thread, where he told a programmer interested in using C++ that they were on the right track for considering why they were using it in the first place, instead of just presuming to use it for the sake of using it.
Once you know what OOP intends to accomplish, though, you start to realize that you can achieve that anyway if you maintain discipline in your programming. So at that point it just becomes a matter of personal preference.
Quote: |
BTW, poslundc- I checked out your environment demo (with the hero from Secret of Mana) on your site... It's quite nice! |
Thank you.
Dan.
#15964 - poslundc - Thu Feb 05, 2004 12:56 am
sajiimori wrote: |
Quote: | If you're not going to use OOP in C++, then for all intents and purposes you are just programming in C anyway.
|
Disagree. But I think it's pointless to argue about it unless we agree on a definition of "object-oriented programming", which nobody really ever does. |
Well let's agree not to open that can of worms, then. :)
Quote: |
My definition of abstraction means encapsulating the repetitive parts, to remove the repitition. What's yours mean? |
I define abstraction to be the encapsulation of a complicated system within a simpler one. Repetition is only one of the potential reasons for doing this. Resumed below...
Quote: |
Quote: |
I can code a module in assembler and if I don't need to worry about its inner workings in order to use it, then it will be abstract.
|
That's right, but you can only abstract certain things. For instance, you can abstract a factorial function, but you couldn't abstract the process of defining functions, or doing 'while' loops, or defining reusable data structures. Every time you want to do those things, you have to repeat the implementation. |
That's true. But C gives you all the tools you need to easily abstract a module from a set of functions and state variables. You don't need objects in order to do so.
Quote: |
Yeah, you have to know how to do it, and also be willing to repeat the 'how' part every time you do it, because you can't abstract the 'how' part away. To use method inheritance, you always have to make a struct with a pointer to a struct that has pointers to functions, but you can't encapsulate that process and put the details into C functions (because C functions can't write structs), or macros (because macros are too stupid). |
I'm not so certain about that... but regardless, it's unimportant because method inheritance is a concept that's native to OOP, and doesn't matter unless you're keen on OOP in which case go ahead and use C++. I can still write a C program that will meet the same specification in an uncomplicated, structured way.
And we agree. :)
Quote: |
But the namespace/package idea is a no-brainer (it's much older than Java). It's a hassle-free way to prevent name clashes. |
How is it any different from name prefixing?
Dan.
#15965 - sajiimori - Thu Feb 05, 2004 1:02 am
Quote: |
C++ asks you to be organized in a certain way, conforming to the OO technique.
|
I still don't see where this 'asking' is happening. Here are a few ways to organize your code in C++:
1 file per module, global functions have prefixes for their module, private functions are declared 'static'. data structures seperate.
1 namespace per module, public functions in their module's namespace, private functions in anonymous namespace. data structures seperate.
1 class per module, functions are static methods, public and private functions are seperated with tags. data structures seperate.
1 class per module, functions are static or instance methods, public and private functions are seperated with tags. data structures are integrated into the class.
The list goes ever on and on...
#15966 - poslundc - Thu Feb 05, 2004 1:12 am
sajiimori wrote: |
Quote: |
I'm saying that OOP - and by extension of that, C++ - lends itself to a certain style of programming.
|
But why argue against a language (for GBA or otherwise) because it lends itself to more styles of programming? How could that possibly be a loss? (My favorite language is Lisp. It lends itself to every style of programming currently known, and all known styles are a subset of Lisp.) |
Well, if we agree that C++ steers you towards OOP (which I don't suppose we do, but humour me) then it really constricts you more than it liberates you.
Quote: |
The danger with C++ is that many programmers think that because they make their program OO that it will automatically be well-designed.
|
Not the fault of the language.[/quote]
Isn't it, though! C++ was invented because people were doing crap jobs of structuring their C programs. You may see it as freeing by providing more ways of doing things, but that's not what it was intended for! It was more like the QWERTY key layout for people who were typing too fast. Learning OOP and learning to properly modularize and structure a program are not one and the same. If you learn the latter, OOP becomes unnecessary.
Dan.
#15967 - poslundc - Thu Feb 05, 2004 1:17 am
sajiimori wrote: |
I still don't see where this 'asking' is happening. Here are a few ways to organize your code in C++:
<snip> |
It's asking you to break your program down into an hierarchy of classes and methods. That's all I'm referring to.
Dan.
#15970 - IGS - Thu Feb 05, 2004 1:31 am
Quote: |
See, here's my beef with OOP. It's a panacea: many programmers think that if they just break down their program into objects they no longer have to worry about proper design [...] It can be useful, but you need to know what you're using it for and why. Otherwise you're just jamming a square peg into what could be a round hole. |
I certainly see your point, which is why I actually started this thread :) We're trying to reason out the best way to accomplish our goals, and I must say that all of the posts so far have been helpful to that end. Even if we continue to use C++, I certainly will be more careful about wasteful coding. I intend to constantly remind myself of the instructions required of my poor GBA for my mad ambition.
We implemented our space shooter in C++ because we both had more experience with C++ than we did with C. Our next project will probably also be coded in C++, but as an additional project we'll recode the shooter in C. It will be a good exercise, and will help us to compare the different ways in which a game might be coded. Anyway, we're trying not to stick any square pegs in round holes... unless the round hole is really really big ;)
Perhaps sometime we'll post our code for public scrutiny (not yet though... it's kinda ugly right now). The feedback would probably do us a bit of good. We did try to put thought into data access and sharing, and which traits should be encapsulated within which objects. I even drew a sweet lil box diagram outlining the channels of communication between objects.
-IGS
#15973 - sajiimori - Thu Feb 05, 2004 1:33 am
Quote: |
That's true. But C gives you all the tools you need to easily abstract a module from a set of functions and state variables. You don't need objects in order to do so.
|
C++ just assists with the process allowing you to explicitly group functions and state, hide the portions that shouldn't be messed with by the outside world, automate initialization and destruction, etc.
Quote: |
How is it any different from name prefixing?
|
While you're in the namespace, you don't have to use the prefix. You can import the namespace into other namespaces and avoid the prefix. Taken together, those things make it more practical to arrange namespaces into a hierarchy, without making function names explode in length.
#15974 - sajiimori - Thu Feb 05, 2004 1:39 am
Quote: |
Well, if we agree that C++ steers you towards OOP (which I don't suppose we do, but humour me) then it really constricts you more than it liberates you.
|
Alright, I'll humor you: Agreed, you win, argument over. OK, done humoring. =)
Why not judge C++ for what it is, rather than why it was invented, or how some people use it?
#15978 - tepples - Thu Feb 05, 2004 2:47 am
sajiimori wrote: |
Why not judge C++ for what it is, rather than why it was invented, or how some people use it? |
In theory, C++ "is" the programming language specified by ISO/IEC 14882. In practice, C++ "is" the body of code written in the language, that is, how some people use it.
Many people use the word "is" dangerously. To help diminish the misunderstandings that forms of "to be" create, Dr. David Bourland invented a subset of English called E-Prime, which lacks "to be". E-Prime can help you keep a more neutral point of view in your writing.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#15981 - poslundc - Thu Feb 05, 2004 3:37 am
I can't think of a better way to end this thread. I am much too exhausted to keep up my end of it.
Dan.
#15984 - sajiimori - Thu Feb 05, 2004 4:43 am
lol... I guess Bill Clinton should have read about E-Prime!
#15992 - pentagram - Thu Feb 05, 2004 4:02 pm
Hi all. Very interesting thread, I would like to add my POV.
There is a concept I miss from the thread: the problem domain. It seems that the whole program needs to be written in a single language or following a single paradigm, and I think that in GBA game programming, the best is to mix up asm, C and C++, thus both procedural and OOP paradigms can be applied in the same program.
In any game, some sort of low level layer is always needed, for example a keypad driver with more advanced features than the simple polling, or an OAM manager. In this domain, C and procedural paradigm is more appropiate, mainly because we are close to the hw, wich is, I agree Dan, inherently procedural.
In the game loop of lets say, a space shooter, the problem domain changes at all. Here the hw has disappeared, all that we have are shoots, ships, explosions, score, lives... In this case the OOP paradigm fits like a glove.
When programming certain screen fx or a sound driver, there are situations where each cycle counts, and then, asm is the choice.
Of course, the OOP paradigm helps to keep the code well organized (again, as long as it is applied to the proper domain), but that isn't free. It has a price because a new level of abstraction is added, and one of the most straighforward examples are the virtual methods. Also, I think that, in general, the engineering process of the OOP paradigm is harder than the procedural approach. Because of that price, it is important to make the choice carefully.
Also, there are situations where choosing OOP might not seem obvious, for example, when working with fixed point numbers. Here, we don't have a complex system of high level objects interacting. However, encapsulating the numbers inside a class with overloaded operators produces a more readable code in the client side. And making the operators inline gives the same eficiency as using the C prepro macros, with the plus of type checking.
cheers.
#15996 - col - Thu Feb 05, 2004 5:13 pm
pentagram wrote: |
Hi all. Very interesting thread, I would like to add my POV.
There is a concept I miss from the thread: the problem domain. It seems that the whole program needs to be written in a single language or following a single paradigm, and I think that in GBA game programming, the best is to mix up asm, C and C++, thus both procedural and OOP paradigms can be applied in the same program.
|
why mix the three?
If you are going to use OOP c++ would be a good choice, in which case, you don't need c at all. Just use c++ and asm. There's no problem writing 'bare metal' procedural code using c++.
Alternatively, if you don't need any of the non c features c++ provides, just use c and asm.
pentagram wrote: |
In any game, some sort of low level layer is always needed, for example a keypad driver with more advanced features than the simple polling, or an OAM manager. In this domain, C and procedural paradigm is more appropiate, mainly because we are close to the hw, wich is, I agree Dan, inherently procedural. |
This is only partly true...
The cpu is inherently procedural, however, the cpu is only part of the hardware in a gba. Much of the work of communicating with the hardware subsystems is done by reading from and writing to fixed data structures, a good example being OAM which is inherently object oriented.
pentagram wrote: |
...
Of course, the OOP paradigm helps to keep the code well organized (again, as long as it is applied to the proper domain), but that isn't free. It has a price because a new level of abstraction is added, and one of the most straighforward examples are the virtual methods.
|
If polymorphism has been applied correctly in well designed system, you should be able to return a net gain in efficiency or at least break even.
pentagram wrote: |
Also, I think that, in general, the engineering process of the OOP paradigm is harder than the procedural approach. Because of that price, it is important to make the choice carefully.
|
Agreed. The initial engineering process using OOP can be longer and more difficult, and for a small project may not be worth it.
As soon as the project or team grows, this extra cost can pay dividends.
cheers
Col
#16001 - sajiimori - Fri Feb 06, 2004 12:53 am
Quote: |
It seems that the whole program needs to be written in a single language or following a single paradigm...
|
I think it's better to use whatever makes each piece of code the best it can be, instead of commiting to a single paradigm and trying to force your whole program to fit it.
Quote: |
In any game, some sort of low level layer is always needed, for example a keypad driver with more advanced features than the simple polling, or an OAM manager. In this domain, C and procedural paradigm is more appropiate, mainly because we are close to the hw, wich is, I agree Dan, inherently procedural.
|
I agree that procedural code usually matches hardware the best. I also agree that most C++ features are not very useful for low-level code, but that's not because C is more procedural. It's because the most significant C++ features are oriented toward large-scale organization, and low-level routines tend to be small-scale. (Also, most of the small-scale features that C++ offers were integrated into C99.)
Anyway, if all your code compiles with a C++ compiler, there's no need to try to seperate code that uses C++ features from code that doesn't. "Switching to C" just means refraining from using C++ features.
#16002 - animension - Fri Feb 06, 2004 1:01 am
I'd like to echo Pentagram's views. When programming, one always needs to consider the terms programmed in. Are we talking to the hardware directly? Then we are most likely going to speak in assembly. Are we taking about taking z = x + (y * 3) >> 8 and then put the result into some routine that transform it some otherway? Procedural programming would seem a good candidate. Are we telling the spaceship to move up the x-axis 5 pixels? OOP would seem like a good paradigm to use.
As far as procedural programming goes, (C - C++) == 0. One *can* use OOP paradigms using pointers to structs and function tables, etc, but if you want to use OOP because it's the best mode to "speak" in for a particular area of your program, why *not* use C++ classes? I can't think of any overriding benefit in using the C paradigm of OOP over the C++ class structure, except personal preference, although I can't imagine why anyone would want to torment themself by purposefully choosing a more complex method over a simpler, more intuitive method when the results will be exactly the same (in the context that one *wants* to use OOP for a task).
_________________
"Beer is proof that God loves us and wants us to be happy."
-- Benjamin Franklin
#16003 - pentagram - Fri Feb 06, 2004 1:04 am
col wrote: |
why mix the three?
...
Alternatively, if you don't need any of the non c features c++ provides, just use c and asm. |
Why not? Once you choose the procedural approach, I think that using C or C++ is a matter of personal taste.
col wrote: |
a good example being OAM which is inherently object oriented. |
It could be, but I don't see it 100% clear. I think that applying OOP to system programming is less straighforward than applying it to the game logic or the GUI.
col wrote: |
If polymorphism has been applied correctly in well designed system, you should be able to return a net gain in efficiency or at least break even. |
Sure, this is the main point. I even might admit a certain loose in efficiency (well, no more than a couple of scanlines per frame ;), because on the long run you will gain in ease of maintenance, reusability, etc. That is the trap where most OOP detractors fall. You need to make an investment at first. Later, you will pick up the benefits.
cheers
#16009 - Andy Friesen - Fri Feb 06, 2004 3:20 am
Even if OO isn't your thing, C++ has a lot to offer. Namespaces, overloads (both operator and function), and templates come to mind. None of these have any impact on the generated code; they merely make it easier to write.
C++ is (almost) a complete superset of C, after all, so it's not hard at all to use the bits that help you express the problem in simpler terms and pretend the others don't exist.
_________________
"Tell a man there are 300 billion stars in the universe and he'll believe you. Tell him a bench has wet paint on it and he'll have to touch it to be sure."
#16037 - sajiimori - Fri Feb 06, 2004 11:04 pm
Well said, Andy.
#16741 - Kavika - Tue Feb 24, 2004 4:50 am
Seems to me the question was pretty broad to begin with 'what should I use, and why?' (not a direct quote, another possible misinterpretation, I'm afraid =)
The question it seems to have been interpreted as was "what is a better language to use, in general?" This, in itself, is a question only answerable by those who are going to be doing the programming. Do you know C++ very well? how well does the rest of your team know C++? Do you know C very well? Does the rest of your team know C++ well? If you answer "yes" to any of these quesitons, then you will be able to answer this question yourself.
It also has been interpreted as "what is a better langauge for programming in general?" If you can answer all four of the above quesitons with "yes", then you are qualified to make this answer yourself. If not, then simply go with what you and your team knows.
An interesting consideration may be why someone who has used both chose to do so. I've personally chosen C++ on some projects, because it helps me program closer to the problem domain, rather than closer to the solution domain. Another way to put this is I'm thinking (more) in human logic terms, not machine terms. This did not put me at a speed disadvantage, due to the "80/20" (90/10) idiom, where ninety percent of processor execution time will be located in 20% or less of the code. I simply optimize this code, and I've got a fairly optimal program.
I've also chosen to use C on some projects, since absolute portability was a requirement. No matter what some people state to the contrary, not every single compiler supports every single C++ feature sufficiently, in speed or correctness. GCC does not exist on every platform I've had to port code to. Forutnately, though, C is simple enough to grasp, and close enough to machine code that there are generally decent, usable compilers for most platforms that are worth the business hours to port to. Again, this is not always true, but in my experience, has been more true for C than for C++.
The C vs C++ debate is pointless. You are the only one fully qualified to make your own decisions. You should do so for yourself, based purely on requirements and adequate domain analysis. If you don't have enough information to make this decision, then research until you do =) Writing software is a decision making process, and there is never a one-size-fits-all solution. If someone offers you one, then consider the source, ignore it, do your own research, and find out for yourself what fits YOUR problem.
The question that seems not to have a definitive answer in this thread (that I saw, I might have missed it) is what is the state of GCC C++ support is on the GBA platform. I haven't personally coded enough in C++ on the GBA to find out what is broken, but everything I tried, at the time, worked properly, compared to how similar code would work on Linux, compiled with the same version of GCC. The only gotcha I _remember_ is to be aware of static initialization issues (which are _always_ a problem, no matter what compiler and platform you use).
Now if you want to consider the source, consider the fact that I actually have much less clout and experience than I've tried to exude in my post. Hah!
Most of what I've regurgitated here is what I remember from reading through the entirety of http://www.parashift.com/c++-faq-lite and the book that corresponds with it. I have little to no _actual_ experience myself with C++, since I've never completed a project in C++ =) Of course, you can consider that software is a living entity, and is never, in fact, complete.
Point is, people can sound like they have valid opinions and experience, with little to no actual practical experience, themselves. I personally couldn't design a complete and proper interface for any given programming task, since I haven't learned enough about software to know what _all_ of the pitfalls are, let alone what _all_ the most useful uses of any particular object are. But I could give a lot of tips on how you should be doing so, if you knew yourself what your problem domain was! ;)
Most people who have posted on this forum, me included, do not have nearly enough experience with both C and C++ to make decisions for you. They may claim to, and they may state random facts as absolute truths, but obviously have little experience, or not enough "correct" experience to make any sort of judgement for you.
The only information I would personally gleen from this forum would be what is broken in the GCC C++ compiler and linker scripts that were ported to work on the GBA target. Anything else is theoretical and purile garbage. Yet again, don't let people tell you what you should be doing, since you're the only person in the position to make that choice.
#16745 - sajiimori - Tue Feb 24, 2004 7:37 am
That sure is a lot to write about a pointless topic, huh?
Maybe you can apply your expertise to solve this dilemma: Why would you call a discussion about the merits of various tools "garbage", and simultaneously put forth an argument about the merits of one of those tools?
#16749 - Miked0801 - Tue Feb 24, 2004 7:56 am
Kavika, good troll. Well written. Insult people, then laugh at yourself. You would be suprised at the level up expertise you will find on this board if you dig a bit.
#16751 - Kavika - Tue Feb 24, 2004 9:07 am
Thanks, I'm new, so bare with me while I get my barings with the whole troll thing ;)
#16752 - Kavika - Tue Feb 24, 2004 9:17 am
So, actually, has anyone found any serious pitfalls with using C++ with kits such as DevKit Advance (if there's anything better at this point, that'd be interesting info too). Specifically, are there any things in specific that are broken or require workarounds?
This was a topic I was interested in, when I was doing GBA dev about 6 months ago, and found most people saying "C++ is bad, use C!"
Not trying to troll this time, honest =) Didn't mean to last time. You'll have to excuse my lack of sleep, and an overdue deadline that's my fault causing me to be more sarcastic and negative than I am normally. Or not, s'up to you =)
TTFN!
#16759 - tepples - Tue Feb 24, 2004 4:27 pm
The point of comments that you may have taken as "C++ is bad" is that the GBA is a much smaller system than many programmers, who have no idea of the costs in bytes and cycles of some of C++'s more expensive operations, are used to.E verything in C that isn't a function call takes O(1) time, making it possible to estimate how fast something in C will run just by looking at the source code; this isn't true of C++, where it's much easier to inadvertently hide over-complexity.
Once you have a bottleneck function working, you may have to look at the generated assembly language code to see how to make it run faster. Many programmers in the OO mindset, who grew up on 500 MHz or faster PCs rather than 1 MHz 8-bit micros, often neglect to do that and just accept slower performance. Just accepting worse performance and footprint doesn't work in soft realtime programming on a small system.
Read more: C vs. C++ on embedded devices
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#16761 - dushan42 - Tue Feb 24, 2004 5:53 pm
Quote: |
E verything in C that isn't a function call takes O(1) time |
Except for macros :)
C++ definitely gives a programmer many new and entertaining ways of shooting him/herself in the foot. That doesn't mean that C is somehow immune.
As fun as it is defending your pet language - ultimately it's not very constructive. We have two toolsets here, where one is a subset of the other and the superset offers both cool features and horrible traps. You can't really tell whether the cool features are worth all the new traps if you don't know the requirements of the project (*) and the skills of the programmer.
In fact I think we might need a "are 'C versus C++' threads worth our time?" thread :)
Enough of this meta drivel, here's some subjective (and probably quite worthless) advice to the original poster:
- stay away from C++ on GBA unless you're 100% fluent in C++
- make the compiler dump out the assembly and check it often for gross inefficiencies (that applies to C code as well)
- if you insist on using C++, avoid:
- templates (note that clever use of templates can be good for performance - but beware of code size explosion)
- virtual methods
- operator overloading
- just avoid anything C++ in inner loops if you're really paranoid
Happy coding!
Dushan
* I guess since we're all writing games here, we can make a pretty good guess about the requirements..
#16768 - torne - Tue Feb 24, 2004 7:09 pm
tepples wrote: |
E verything in C that isn't a function call takes O(1) time, making it possible to estimate how fast something in C will run just by looking at the source code; |
*nitpick* Not true even on an architecture as simple as the GBA's; memory access timings are variable depending on context and on prefetch applicability, and whether things are in memory or in registers in the first place will vary depending very much on what you write (and not even in a way that's easy for most people to predict). It's certainly not true on a modern superscalar system like the P7 microarch or the AMD64, where the microcode being executed often seems unrelated to the assembly code you wrote, let alone to high-level code. =)
Personally I don't find C++ to contain more abstractions; every vaguely objecty abstraction which I use in C++ or Java I can and do also use in C or even in assembler; it's all about seeing the abstract and concrete together (both the problem-domain abstractions that you are using, and the code you predict will be generated).
#16773 - poslundc - Tue Feb 24, 2004 9:33 pm
torne wrote: |
*nitpick* Not true even on an architecture as simple as the GBA's; memory access timings are variable depending on context and on prefetch applicability, and whether things are in memory or in registers in the first place will vary depending very much on what you write (and not even in a way that's easy for most people to predict). |
Neither of these factors change the timing complexity from being O(1).
Dan.
#16775 - torne - Tue Feb 24, 2004 9:56 pm
Yes they do. The same code called in different contexts can have different execution times, thus it's not constant-time. Also the multiply instruction takes different time on different arguments and thus any construct which requires multiplication is definately not O(1).
#16776 - poslundc - Tue Feb 24, 2004 10:12 pm
torne wrote: |
Yes they do. The same code called in different contexts can have different execution times, thus it's not constant-time. Also the multiply instruction takes different time on different arguments and thus any construct which requires multiplication is definately not O(1). |
O(1) multiplied by any other constant length of time is still O(1). Big-Oh notation refers to complexity, not the actual execution time.
Put another way: if I call the MUL instruction a million times with bits [31..8] of Rs all zero, and then if I call the MUL instruction a million times again, but with a one somewhere in bits [31..24], the second run will definitely take longer than the first run, but they are still the same timing complexity. Complexity refers to how the timing changes as the function grows, and in both cases the timing responds to growth in the same way.
Dan.
#16777 - torne - Tue Feb 24, 2004 10:52 pm
poslundc wrote: |
O(1) multiplied by any other constant length of time is still O(1). Big-Oh notation refers to complexity, not the actual execution time. |
Yes, I know that. However, if the execution time changes depending on the size of the input, it can't be constant complexity. =)
Quote: |
Put another way: if I call the MUL instruction a million times with bits [31..8] of Rs all zero, and then if I call the MUL instruction a million times again, but with a one somewhere in bits [31..24], the second run will definitely take longer than the first run, but they are still the same timing complexity. Complexity refers to how the timing changes as the function grows, and in both cases the timing responds to growth in the same way. |
Complexity has nothing to do with repeated execution. Ignore the million times in the above, and notice that larger operands (i.e. ones with high bits set) take more time than smaller operands (ones with no high bits), and likewise, 32x32=64 multiplies take longer still. Multiplication grows as a function of the magnitude of the operands (I don't know the exact function because I don't know which implementation of multiplication the ARM7 uses off the top of my head, and the notes for the course in which the exact time function of ARM7 multiplication were given are not online) and is thus a non-constant function of n.
#16779 - poslundc - Tue Feb 24, 2004 11:15 pm
torne wrote: |
Complexity has nothing to do with repeated execution. |
Actually, it has almost everything to do with repeated execution. Complexity applies to algorithms; any fixed-length set of instructions that never repeats automatically has a complexity of O(1).
The situation where you multiply two numbers a and b results in four different possible timings, but the internal algorithms used for each case are all O(1), even though there are four distinct possibilities. In the same way, different timings for memory accesses are all O(1) as well.
Quote: |
Multiplication grows as a function of the magnitude of the operands |
To make this absolutely clear: it grows in the amount of time it takes, it grows in the number of cycles it consumes. It does not grow in complexity, however. The algorithms used to multiply both a big number and a small number are the same complexity, which is O(1).
Dan.
#16781 - Kavika - Tue Feb 24, 2004 11:30 pm
Agreed. Since it's designed to utilize encapsulation inside the language and library itself, there's no guarantee of what's going on inside most of your C++ program, only the guarantee (if the compiler/library implementors did their job correctly) that they'll behave a certain way, under certain conditions. Linear or logarithmic time doesn't guarantee what the constants in the function will be, only it's curve ;)
That's when you look to trusty Mr. profiler (another thing I have no experience with, but know that I should be using) and, to a lesser extent, Mr. debugger... It doesn't take much to figure out that if your drawing routine waits to sync with the screen, but you're only getting 30fps, that the routine is taking up too much time. However, Mr. profiler will tell you exactly which part of your update routine you need to fix or redesign, instead of blindly stumbling through, or relying on intuition, which imperically has been proven ineffective (bold generalization here, of course. I'm too lazy to go find someone to quote on this, plus it's my 15 minute break =)
I personally see no problem mixing C, C++, and ASM, provided you know what you are doing. To the best of my knowledge (which is admittedly not as much as I'd like), GCC didn't care which of the three GCC tools you used to compile, as long as you used their tools and linker for the whole job.
Again, this may be a case where the GBA port of the tools is broken. I'd really love to hear more imperical evidence one way or the other. If people have found nothing is broken, then C++ and ASM mix sounds like the way to go for those in the know! =) If C++ is broken, then it'd be nice to find out why, so they can either be fixed, or figure out workarounds, possibly post them in some FAQ or something.
I'd personally find this much more interesting than bringing the _pure_ C/C++ debate to yet another forum, since, like abortion, it's one of those eye of the beholder things. Just so we're on the same page here, yeah I know that not all beginners have seen all sides of this debate. I'd just like to see the stuff I stated in the previous paragraph, since I haven't found any comprehensive info on this yet.
#16815 - torne - Wed Feb 25, 2004 1:53 pm
poslundc wrote: |
Actually, it has almost everything to do with repeated execution. Complexity applies to algorithms; any fixed-length set of instructions that never repeats automatically has a complexity of O(1). |
Your statement implies that any instruction sequence which has no looping or recursion is constant-time; this is approximately true, but the multiplication algorithm contains a loop! The loop early-terminates when there is less work to be done, which is operand-dependant.
Quote: |
The situation where you multiply two numbers a and b results in four different possible timings, but the internal algorithms used for each case are all O(1), even though there are four distinct possibilities. |
No, there are not four distinct possibilities. There are four possible execution times, but that's only because the ARM is a synchronous processor and thus all execution times are rounded up to the nearest whole processor cycle, and the maximum is fixed due to the word size being limited (and is thus the worst-case time for 32x32=32 multiplication). The Amulet, the asynchronous ARM, can take any execution time in a continuous range to perform a multiplication of two 32-bit integers; its range's maximum is the same as the ARM's (give or take the fact that the Amulet doesn't have to round up to whole clock cycles) but the minimum is far lower (for example, multiplying by zero). There are not four distinct possibilities; there are 32^2 possibilities; one for each possible pair of operands; some of them just happen to take the same time. All pairs of operands result in different paths through the algorithm (with the possible exception of pairs with the operands exchanged, but perhaps not even that).
Quote: |
To make this absolutely clear: it grows in the amount of time it takes, it grows in the number of cycles it consumes. It does not grow in complexity, however. The algorithms used to multiply both a big number and a small number are the same complexity, which is O(1). |
It does not use a different algorithm for large and small numbers; it uses the same looping algorithm for all numbers, with early termination causing the difference in runtime (by reducing iterations).
#16817 - poslundc - Wed Feb 25, 2004 3:31 pm
Yes, the algorithm contains a loop, and yes, it is early-terminated. The point is that it's limited by a constant factor - I'm guessing the ARM uses standard digit-by-digit multiplication, which means this factor is the smaller number of binary digits in the operands - you cannot examine its steady-state behaviour as n approaches infinity because the behaviour of the function has already been charted for every possible value of n.
I agree that the pure multiplication algorithm would be O(n) (where n is the minimum number of digits in the parameters), and if you rewrote it in software to handle any possible number that would be its complexity. The multiplication instruction on ARM machines is O(32), however, which is the same as O(1).
Dan.
#16822 - torne - Wed Feb 25, 2004 4:06 pm
poslundc wrote: |
The point is that it's limited by a constant factor - I'm guessing the ARM uses standard digit-by-digit multiplication, which means this factor is the smaller number of binary digits in the operands - you cannot examine its steady-state behaviour as n approaches infinity because the behaviour of the function has already been charted for every possible value of n. |
Your logic is arguably correct but useless, IMO. If you choose O(1) as the complexity for anything which has an upper bound on its inputs, then every single operation which can be performed by a computer (as they all have upper bounds on their input size mostly related to how much storage you have) is O(1) because you *could* precalculate all the answers and store them in a lookup table, even problems which in the abstract are exponential-time or worse. You could even look at it from a state-space POV and note that all calculable functions must have bounded inputs because there are only so many possible states for the entire universe, thus all calculable functions are O(1).
Complexity theory is about discussing things in the abstract; there is not much reason to discuss the complexity bound of a function whose implementation is known and input range is finite, as the exact bound is calculable. If you intend to discuss the actual concrete runtime of the ARM multiplication instruction, it's quite possible to instead give the function which maps all possible operands to their corresponding execution time. Making sweeping statements about all C code which does not iterate or recurse being O(1) are untrue unless referring to a specific implementation with its own specific upper bounds; for example, there does exist a C compiler (though I'll be buggered if I can find it now) which uses bigints for all numeric values (a la PolyML), thus the code 'x = x * x' can take time bounded only by the amount of memory you have available to store the initial value of x, which on an abstract machine, is unspecified and can be assumed to be infinite =). This complies just fine with the C specification, which only issues relative and lower bounds on the size of integer types.
So yes, you cannot really examine the steady-state behaviour of ARM multiplication, as you said. So why were you? =) O(1) is a steady-state behaviour bound, just the same as O(n) is.
#16826 - poslundc - Wed Feb 25, 2004 4:54 pm
torne wrote: |
Your logic is arguably correct but useless, IMO. If you choose O(1) as the complexity for anything which has an upper bound on its inputs, then every single operation which can be performed by a computer (as they all have upper bounds on their input size mostly related to how much storage you have) is O(1) because you *could* precalculate all the answers and store them in a lookup table, even problems which in the abstract are exponential-time or worse. You could even look at it from a state-space POV and note that all calculable functions must have bounded inputs because there are only so many possible states for the entire universe, thus all calculable functions are O(1). |
You answer this yourself further down. Time-complexity analysis is relevant to understanding algorithms and how they will behave as the size of their input grows. Parallel computing aside, ARM has already laid out the timing of the multiply instruction in four distinct possibilities, all of which are constant time. There is no algorithm you could conceive of in C (or any other programming language, for that matter) that would gain or lose complexity by using that multiply instruction on a set of numbers that are very large or very small.
Quote: |
Making sweeping statements about all C code which does not iterate or recurse being O(1) are untrue unless referring to a specific implementation with its own specific upper bounds; for example, there does exist a C compiler (though I'll be buggered if I can find it now) which uses bigints for all numeric values (a la PolyML), thus the code 'x = x * x' can take time bounded only by the amount of memory you have available to store the initial value of x, which on an abstract machine, is unspecified and can be assumed to be infinite =). This complies just fine with the C specification, which only issues relative and lower bounds on the size of integer types. |
Well I'll congratulate you on finding an exception to what tepples said, but I'll also remind you that I never said anything about all C code being able to do anything. I just said that neither variable access times, register load/stores, or (in the following post) different timings for the multiply instruction will alter the timing of an already O(1) algorithm, and I stand by that. If you want to challenge tepples on his statement then you're welcome to it, but I've clearly staked out my area of expertise and discourse, and damned if I'll be tricked into wandering beyond it! :)
Quote: |
So yes, you cannot really examine the steady-state behaviour of ARM multiplication, as you said. So why were you? =) O(1) is a steady-state behaviour bound, just the same as O(n) is. |
Clever. But O(1) is the same as saying it has no steady-state behaviour. It would be the "0" unit of the complexity-analysis vector-space. Assuming that complexity-analysis is a vector-space, something I'm not prepared (or really at all inclined) to check.
Dan.
#16827 - torne - Wed Feb 25, 2004 5:43 pm
poslundc wrote: |
Well I'll congratulate you on finding an exception to what tepples said, but I'll also remind you that I never said anything about all C code being able to do anything. I just said that neither variable access times, register load/stores, or (in the following post) different timings for the multiply instruction will alter the timing of an already O(1) algorithm, and I stand by that. If you want to challenge tepples on his statement then you're welcome to it, but I've clearly staked out my area of expertise and discourse, and damned if I'll be tricked into wandering beyond it! :) |
Until you just pointed it out I thought you were the one who'd made the original statement. I didn't notice that I was replying to a different person. *smacks head*
I can conceive of memory systems which exhibit non-linear access complexity (not pointlessly, actually to serve a purpose), though they're very unlikely to actually exist anywhere and are far too weird to really explain. *grin*
Quote: |
Quote: | So yes, you cannot really examine the steady-state behaviour of ARM multiplication, as you said. So why were you? =) O(1) is a steady-state behaviour bound, just the same as O(n) is. |
Clever. But O(1) is the same as saying it has no steady-state behaviour. It would be the "0" unit of the complexity-analysis vector-space. Assuming that complexity-analysis is a vector-space, something I'm not prepared (or really at all inclined) to check. |
I diagree with that; a O(1) bounded function has steady-state behaviour of never being higher than some unspecified constant, just as O(n) has the behaviour of never being higher than some unspecified function of n. I don't think complexity is a vector space, either. I might well ask one of the theorists at the next happy hour. =)
The point I was really trying to make was not a theoretic one about complexity, but a counter to what tepples' original statement said, particularly the "making it possible to estimate how fast something in C will run just by looking at the source code" part. The point that I misplaced while diverging into complexity theory and obscure counterexamples was that it is *not* possible to have an intuitive understanding of the speed of something written in C, even an estimated one, because the most unexpected things affect the runtime in drastic ways. On the GBA it is possible to intuitively analyse runtime of assembly code (as there is no cache to screw up static timing analysis), but compiler code generation adds a layer of obfuscation beyond which you can't really see (especially with moderate to extreme levels of optimisation). Even I sometimes can't accurately predict the generated code for a given chunk of C. =)
#16829 - poslundc - Wed Feb 25, 2004 6:08 pm
torne wrote: |
I don't think complexity is a vector space, either. I might well ask one of the theorists at the next happy hour. =) |
I think I am wrong about this, because O(1) behaves as 0 in terms of addition and as 1 in terms of multiplication, so I'm not really sure where it fits in and its been about five years since I cracked a textbook on the matter. :P
Quote: |
On the GBA it is possible to intuitively analyse runtime of assembly code (as there is no cache to screw up static timing analysis), but compiler code generation adds a layer of obfuscation beyond which you can't really see (especially with moderate to extreme levels of optimisation). Even I sometimes can't accurately predict the generated code for a given chunk of C. =) |
Well, the problem is we're looking at different scopes. I believe what tepples' original post was saying is something along the lines of any primitive C statement - in its implementation - has O(1) complexity, and that's generally true even if you have no clue what kind of ridiculous assembly code and memory timing issues may come out of it. Lord knows I can't predict what gcc will do 99% of the time, but I know that even if a simple statement ends up increasing my code by 10, 50, or even 100 cycles the complexity of my algorithm will remain the same. It might be very important to me that I'm taking all of those extra cycles, but that's an issue of timing, not timing complexity.
Your wacky multiply-any-two-numbers-with-unbounded-precision language may be an exception to that, but that's not an area that I feel I have the necessary background in to formulate an informed opinion on it.
Dan.
#16832 - torne - Wed Feb 25, 2004 6:21 pm
poslundc wrote: |
torne wrote: | I don't think complexity is a vector space, either. I might well ask one of the theorists at the next happy hour. =) |
I think I am wrong about this, because O(1) behaves as 0 in terms of addition and as 1 in terms of multiplication, so I'm not really sure where it fits in and its been about five years since I cracked a textbook on the matter. :P |
I don't have much of an idea. Theory was never my strongest point =)
Quote: |
Well, the problem is we're looking at different scopes. |
This is the root of the argument, yep. Should've noticed earlier, really =)
I consider everything in terms of the micro, because the macro is 'obvious'. When I write Java code, I think in terms of the just-in-time compiled and optimised assembly code it'll generate (obviously, I think about the OO abstractions too; but those are part of *design*; I consider the former to be part of the implementation even though I don't directly write it). Likewise, when I'm programming in C, I know I'm already using an algorithm with sufficiently low complexity (because otherwise I wouldn't've used it) and I am thus more interested in actual cycle timings.
You could say that I program in assembler whatever language I'm using. =)
Quote: |
Your wacky multiply-any-two-numbers-with-unbounded-precision language may be an exception to that, but that's not an area that I feel I have the necessary background in to formulate an informed opinion on it. |
I can't find the C implementation (it was pretty damn obscure in the first place), but PolyML, an implementation of the functional language ML, has unbounded arithmetic for both integers and real numbers (and can do exact rational numbers too). If you were interested you can easily find it with Google. =)
#16838 - sajiimori - Wed Feb 25, 2004 7:23 pm
libgmp is the GNU library for arbitrary precision math.
Other languages that support arbitrary precision ("bignums") include Haskell, Ruby, Python, and most Lisps.
#16854 - torne - Wed Feb 25, 2004 11:13 pm
sajiimori wrote: |
libgmp is the GNU library for arbitrary precision math. |
The thing I was thinking of was a compiler, not a library; it treated *all* numeric data types in an unmodified C program as bignums, not just things declared as such; i.e. all int/short/long/float/double values. It used the same promotion/demotion scheme as PolyML to store them and process them with a moderate amount of efficiency (basically, using a finite-sized datatype for values until they became too large or precise, and then being able to 'promote' them).
#17637 - maximAL - Thu Mar 11, 2004 7:08 pm
something else about C++/OOP and GBA
it really seems to be pain in the ass to write a usefull, mostly overhead-free framework to access the hardware.
actually, it should be no problem to build some classes that perfectly fit into the memory registers of the GBA. rebuilding the regs with bitfields (or plain shifting if you prefer) is very easy, add some nice functions to it and voila, you could use sprites, tiles etc. as objects without much (or any?) overhead.
but all the time you have to struggle with these damn memory acces limitations. you can't do byte-writes to VRAM? bitfields won't work, too? oh, and 16 bit classes (eg. tiles) get inflated to 32 bit, so they don't fit into the regs anymore. did i mention that using __attribute__((packed)) causes data to be corrupt, just like byte-writes?
yeah, so much for a nice, tiny OOP api for the GBA...
#17657 - sajiimori - Fri Mar 12, 2004 12:46 am
Abstracting over real-world hardware can be tough -- most systems are nowhere near 100% orthogonal. GBA is actually better than average in that regard.
Usually, the trick is to find the right level of abstraction for each hardware feature. You want to find something that just barely hides the hardware, and doesn't prevent client code from fully taking advantage of it.
For instance, abstracting single pixel writes for mode 4 is not really optimal, because you couldn't take advantage of the speed gains from writing pairs of pixels at a time. plot_pair(offset, color_pair) and read_pair(offset) would be better initial abstractions. You could implement other functions like plot_pairxy(x, y, color_pair) and plotxy(x, y, color) in terms of those, if desired.
Since bitfields aren't reliable, shifting is just fine. Even when bitfields do work, I've heard gcc generates slow code for them.
32-bit values fit in registers, so it's ok if gcc produces 32-bit objects. In fact, it's usually better.
I wouldn't bother trying to get structs to line up with the hardware, either. Just do it by hand once, then forget about it.
Of course, all this stuff should be inlined.
#17667 - tepples - Fri Mar 12, 2004 3:26 am
sajiimori wrote: |
I wouldn't bother trying to get structs to line up with the hardware, either. |
That's because I've already bothered for you. Every project on my GBA page includes 'pin8gba.h', which represents a lot of the GBA hardware registers with structs, arrays, and arrays of structs. The version in the GSM player source distribution is the most recent version and the most complete and accurate.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#17687 - maximAL - Fri Mar 12, 2004 5:21 pm
sajiimori wrote: |
32-bit values fit in registers, so it's ok if gcc produces 32-bit objects. In fact, it's usually better. |
but when you happen to need a 16 bit object, it just plain sucks that theres no way in hell you could get it working.
#17697 - sajiimori - Fri Mar 12, 2004 7:22 pm
Quote: |
Every project on my GBA page includes 'pin8gba.h', which represents a lot of the GBA hardware registers with structs, arrays, and arrays of structs.
|
Neat. Does ANSI C guarantee that the 16 bit members won't be padded to 32 bit, or is it just rare in practice?
Quote: |
but when you happen to need a 16 bit object, it just plain sucks that theres no way in hell you could get it working.
|
Like when?
#17700 - maximAL - Fri Mar 12, 2004 7:55 pm
sajiimori wrote: |
Like when? |
like when creating a tile-class. and text-map entries are 16 bit.
of course you can always do it some different way. but thats not necessarly a good way.
#17704 - tepples - Sat Mar 13, 2004 12:03 am
sajiimori wrote: |
tepples wrote: | 'pin8gba.h', which represents a lot of the GBA hardware registers with structs, arrays, and arrays of structs. |
Neat. Does ANSI C guarantee that the 16 bit members won't be padded to 32 bit, or is it just rare in practice? |
Field alignment in a class or struct is implementation defined. GCC aligns each field in a struct to a multiple of the field's align-size. On RISC processors such as ARM, the align-size of an integer or pointer equals its size in bytes, and the align-size of a struct is the largest align-size of its fields. Thus:- A struct consisting of two 16-bit fields (e.g. struct BGPOINT for text background scrolling) will be packed into four bytes
- A struct consisting of two 32-bit fields and two 16-bit fields (e.g. struct DMACHN) takes 12 bytes.
- A struct consisting of four 16-bit fields and two 32-bit fields (e.g. struct BGAFFINEREC) takes 16 bytes.
C++ complicates things by adding a pointer to a virtual function table to some classes.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#17708 - sajiimori - Sat Mar 13, 2004 12:34 am
Even tile objects needn't be 16 bits, despite the hardware. If the goal is to abstract over the hardware, then whichever function handles tile reads/writes can be made to do the right thing regardless of the object's size.
If you're worried because you can't access tile maps as arrays of tile objects when the objects are the wrong size, that isn't very abstract at all. Isn't the goal to avoid accessing the hardware directly?
#17715 - Andy Friesen - Sat Mar 13, 2004 1:56 am
tepples wrote: |
C++ complicates things by adding a pointer to a virtual function table to some classes. |
It's not complicated at all. If the struct has no virtual members, and doesn't inherit anything which does, then it has no vtable.
_________________
"Tell a man there are 300 billion stars in the universe and he'll believe you. Tell him a bench has wet paint on it and he'll have to touch it to be sure."