#18950 - mr_schmoe - Thu Apr 08, 2004 4:37 pm
I have an pallete stored in a const array that I want to load via function, i.e. loadpallete(u16* palletedata). But I get this stupid error saying it can't convert my pallete array to the u16*. Can anyone help me? If you need more information on what I'm trying to do, let me know.
#18953 - beelzebub - Thu Apr 08, 2004 5:33 pm
add a const to you function prototype
void loadpalette (const u16* palletedata)
providing your function doesn't modify the data you'll still be able to pass non-const data (dynamic palette info) into the function.
#18956 - Miked0801 - Thu Apr 08, 2004 6:21 pm
How are you passing the array to the function? What is the code?
#19054 - mr_schmoe - Sat Apr 10, 2004 7:39 pm
the code is something like this.
Code: |
const u16 spritedata[] = {0x1435, 0x2453, ..., 0x0001 }
...
void loadsprite(u16* spritedata)
{
// copy sprite data to OAM mem
...
}
|
but I got it working by putting a const in my function declaration
Code: |
void loadsprite(u16* spritedata); |
is there a better way to do this?
#19057 - Gopher - Sat Apr 10, 2004 8:47 pm
no, there is not a better way to do this. Const makes it read-only. const globals are stored in ROM. non-const would be stored in RAM. you can't pass a const pointer to a function unless it expectes it to be const as well.
This solution was adding 10 letters and 2 spaces to your code. (half to .h, half to .c) That's not a good enough solution for you? :)
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#19058 - poslundc - Sat Apr 10, 2004 8:53 pm
Gopher wrote: |
no, there is not a better way to do this. Const makes it read-only. const globals are stored in ROM. non-const would be stored in RAM. you can't pass a const pointer to a function unless it expectes it to be const as well. |
*cough* typecasting *cough*
Dan.
#19060 - Cearn - Sat Apr 10, 2004 8:57 pm
mr_schmoe wrote: |
the code is something like this.
Code: | const u16 spritedata[] = {0x1435, 0x2453, ..., 0x0001 }
...
void loadsprite(u16* spritedata)
{
// copy sprite data to OAM mem
...
}
|
but I got it working by putting a const in my function declaration
Code: | void loadsprite(u16* spritedata); |
is there a better way to do this? |
Uhm ... what's changed in the second version? The argument of loadsprite is still non-const. Or is that a simple typo?
Anyway, when you give a variable the const specifier, you tell the compiler that no-one is allowed to mess with its contents. For example, if you tried something like
Code: |
spritedata[0]= 0xb1aa;
|
in your code (aside from in the definition, of course), the compiler wouldn't let you get away with it. But when passing it to a function (like loadsprites), the constness of the variable should be preserved. However, with a const-less argument declaration, you're basically saying that the variable is allowed to be modified inside the function, thus negating the whole concept of constness. By using the const specifier, you're letting the compiler (and the programmers working with the code) know that the function would be messing with the variable's contents, so it's OK to pass
a const pointer to the function.
As beelzebub said, you can still use a non-const variable as a const argument, since it's OK to leave a variable as it is. The reverse, however, will and should get you into trouble, as you discovered.
EDIT: argh, too late. What Gopher said, basically.
And Dan, are you sure it can be avoided by a simple typecast? Didn't know that. Omg, that is nasty.
Last edited by Cearn on Sat Apr 10, 2004 9:09 pm; edited 1 time in total
#19063 - poslundc - Sat Apr 10, 2004 9:06 pm
Cearn wrote: |
As beelzebub said, you can still use a non-const variable as a const argument, since it's OK to leave a variable as it is. The reverse, however, will and should get you into trouble, as you discovered. |
*cough again* typecasting *cough again*
Dan.
#19065 - tepples - Sat Apr 10, 2004 9:10 pm
poslundc wrote: |
*cough again* typecasting *cough again*
Dan. |
Typecasting often does get you into trouble. It's best to think out what should be const in the header files.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
#19067 - poslundc - Sat Apr 10, 2004 9:14 pm
tepples wrote: |
It's best to think out what should be const in the header files. |
Fair enough. But typecasting works just fine if you mind what you're doing, and it becomes necessary (in C anyway) if you want to handle polymorphic situations (as I often do, since the data used for an image or whatever could be coming from the ROM or from, say, EWRAM).
Dan.
#19069 - tepples - Sat Apr 10, 2004 9:24 pm
If the data comes from EWRAM, it's perfectly OK to pass it to a function that expects const data. For example, in the official POSIX prototype for memcpy(): Code: |
void *memcpy(void *restrict s1, const void *restrict s2, size_t n); |
it's perfectly fine to pass a pointer to non-const to a function that expects a pointer to const; otherwise, copies from the heap to the heap in PC programs wouldn't work.
In general, C and C++ will automatically add the const and volatile qualifiers when needed, but it takes an explicit cast to remove them. (Ignore the "restrict" parts; they refer to a new optimization hint added in C99, which the version of GCC in DevKit Advance R5 beta 3 does not implement.)
I may have misunderstood you. If so, please provide a code sample so that I can better understand what you mean.
_________________
-- Where is he?
-- Who?
-- You know, the human.
-- I think he moved to Tilwick.
Last edited by tepples on Sun Apr 11, 2004 2:05 am; edited 1 time in total
#19071 - Gopher - Sat Apr 10, 2004 9:35 pm
dan, are you actually saying that typcasting away consts is a better solution than adding const to the parameter? In what way is it BETTER than adding const? it's more keystrokes, and must be done per-call, rather than once for the whole function, so it's not better than that.
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#19073 - poslundc - Sat Apr 10, 2004 10:35 pm
Prototyping your function as accepting a const is just fine, and probably the best and most programmatically sound way to go about it the majority of the time. I was simply responding to the two statements that there was no way to pass a constant parameter to a non-constant function, and that it would cause trouble (with the compiler) to do so.
So no, I'm not saying that typecasting is a better solution than adding const to the parameter. But sometimes it may be desirable not to add the const qualifier to the parameter. This would apply to situations where you aren't doing it because you care about the constancy of the data in your function (even it if it is being kept constant), but are only doing it for the sake of making it accept read-only data without typecasting.
Tepples: are you certain that GCC will automatically promote to const? I was under the impression that it didn't, although I haven't tested it in a very long time. (I seem to recall that it at least generated a warning.) You can, of course, cast in either direction.
I just prefer not to use the const qualifier unless it's something I'm overtly thinking about in my module's design. Putting the "const" qualifier implies to myself that I have a reason to, and it should be better than just wanting to make the parameter-passing seamless. This is my own personal quirk, and not something I would necessarily expect others to identify with.
Dan.
#19077 - Gopher - Sat Apr 10, 2004 10:40 pm
I don't quite follow your argument; the only reason I can think of would be if you for some reason can't (or shouldn't) change the function's qualifiers, either because you only have headers or because you're working with a team and it's someone else's code.
As for adding const, yes, every c compiler will ADD const if needed. memcpy() takes a const char* for it's source, but I'm sure you've called it many times with non-constant source pointers and just never even noticed it. :)
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#19080 - torne - Sat Apr 10, 2004 10:52 pm
GCC always promotes to const silently if needed (there might be some obscure warning option somewhere which makes it squeal, but '-W -Wall' doesn't). You shouldn't ever cast away constness (it might break the optimiser in some very obscure cases), especially not in an environment that puts global const data in a .rodata section (like, say, devkitadvance *grin*).
#19083 - poslundc - Sat Apr 10, 2004 11:29 pm
Gopher wrote: |
I don't quite follow your argument; the only reason I can think of would be if you for some reason can't (or shouldn't) change the function's qualifiers, either because you only have headers or because you're working with a team and it's someone else's code. |
One reason is having to propagate the const through multiple levels of function calls. Which is not something I'm inclined to do if the constancy isn't something I care to deal with. It's not an argument I can defend in terms of being well-structured - because I can't - only in terms of being too lazy to put "const" everywhere, especially when I haven't really analyzed my reason for doing so beyond wanting to accept pointers from the read-only sections.
Quote: |
As for adding const, yes, every c compiler will ADD const if needed. memcpy() takes a const char* for it's source, but I'm sure you've called it many times with non-constant source pointers and just never even noticed it. :) |
Actually, I've never called memcpy. It's broken in my version of DKA.
torne wrote: |
You shouldn't ever cast away constness (it might break the optimiser in some very obscure cases), especially not in an environment that puts global const data in a .rodata section (like, say, devkitadvance *grin*). |
<shrug> You can if you're careful about it. But no, I probably wouldn't want to do it on a project with more than one person involved.
Dan.
#19086 - torne - Sat Apr 10, 2004 11:48 pm
poslundc: Make all arguments to everything const by default, and only remove it when neccecary?
#19089 - poslundc - Sun Apr 11, 2004 12:12 am
torne wrote: |
poslundc: Make all arguments to everything const by default, and only remove it when neccecary? |
Nuts to that. :)
Dan.
#19091 - Gopher - Sun Apr 11, 2004 1:24 am
poslundc wrote: |
It's not an argument I can defend in terms of being well-structured - because I can't - only in terms of being too lazy to put "const" everywhere, especially when I haven't really analyzed my reason for doing so beyond wanting to accept pointers from the read-only sections.
|
ok. Easy to address. You tell the compiler that you won't change the parameter by making it const. This allows the compiler to make optimizations that assume there wont need to be any write-back of that value when it is read. Removing the consts to pass them into functions also opens the possibility that a module might try to write there, which won't work if it's a const global on gba stored in rom. Of course, ultimately no argument can trump laziness, but it still seems to me that it's more work to typecast all the time.
poslundc wrote: |
Actually, I've never called memcpy. It's broken in my version of DKA.
|
You've never programmed anything besides gba?
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#19092 - torne - Sun Apr 11, 2004 1:52 am
Gopher wrote: |
This allows the compiler to make optimizations that assume there wont need to be any write-back of that value when it is read. |
Actually for function parameters it doesn't help the optimiser much in most cases because the procedure call standards on most architectures (including ARM) requires the compiler to assume that the value is destroyed regardless. Recent gcc versions can do very limited cross-function optimisation on static functions whose addresses are not taken, however, which will let you exploit this a bit. In general, though, it won't actually help =)
#19093 - Gopher - Sun Apr 11, 2004 2:03 am
torne wrote: |
Actually for function parameters it doesn't help the optimiser much in most cases because the procedure call standards on most architectures (including ARM) requires the compiler to assume that the value is destroyed regardless.
|
Didn't realise that; seems odd, but I assume there's reasoning to it that I am unaware of.
_________________
"Only two things are infinite: the universe, and human stupidity. The first is debatable." -Albert Einstein
#19098 - poslundc - Sun Apr 11, 2004 5:33 am
Gopher wrote: |
poslundc wrote: |
Actually, I've never called memcpy. It's broken in my version of DKA.
|
You've never programmed anything besides gba? |
I was referring to GBA programming, which I think could be inferred by the mention of DKA and this being a GBA programming forum.
Dan.
#19111 - torne - Sun Apr 11, 2004 2:20 pm
Gopher wrote: |
torne wrote: |
Actually for function parameters it doesn't help the optimiser much in most cases because the procedure call standards on most architectures (including ARM) requires the compiler to assume that the value is destroyed regardless.
|
Didn't realise that; seems odd, but I assume there's reasoning to it that I am unaware of. |
Most compilers in most circumstances compile functions pretty much in isolation from each other. Using ARM as an example, the compiler thus has to assume that all function calls trash the contents of r0-r3 and ip. r0-r3 are the same registers used for the first four function arguments, so although the compiler can technically look and see 'ooh, the first argument is const', it still can't assume that r0 will be unchanged by the time the function returns (it's perfectly valid for the code to overwrite r0 later at some point after it's finished using the value of the first parameter). The only time you can 'peer into' the other function and see what it actually does is when you know exactly which other function will be called (i.e. it's in the same file) and in almost all circumstances you can't do anything useful with this information, because it would generally violate the procedure call standard (not doing so is vital to make operating system loaders, libraries, and linkers work in the way that you expect). As I said, GCC can sometimes do optimisations on static functions whose addresses are not taken, because these functions are guarenteed to only be called from within the current file, and thus as long as they work correctly in all the calls in this file, nothing else matters. I don't actually know whether these optimisations are present in any release version of GCC; I suspect not (it's all a bit experimental and strange).