It is currently Sun Oct 21, 2018 4:59 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 10 posts ] 
Author Message
PostPosted: Fri Jun 22, 2018 8:18 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2008
Location: Fukuoka, Japan
I have been playing with C code in cc65 these days and I have a small issue that right now doesn't hinder my testing but would like to know what I'm doing wrong. I didn't write C code for ages so it may be something that I don't know anymore about.

I will explain with some example so it will be easier to understand. First, what works.

For example, the smallest element, a list of sprite that forms a meta-sprite, ends up in rodata:
Code:
const unsigned char standing1[] = {
   0x00, 0x00, 0x0B, 0x40,   // Head top 1 
...
128};

My list of meta-sprite that makes an animation list ends up in rodata:
Code:
const unsigned char* const standingAnim[2] = {
   standing1,
   standing2
};

But my list of animation ends up in data:
Code:
const unsigned char* const *heroAnimList[5] = { standingAnim, ...,  runningAnim };

The goal is to able to retrieve the proper animation list based on the current state of the actor:
Code:
// List of animation
typedef enum {
   STANDING = 0,
   WALKING,
   WALKING_GUN,
   JUMPING,
   JUMPING_GUN
} animState_t;

....
hero.anim.frameList = heroAnimList[STANDING];

My guess is on how I define my list with const but I didn't work in C for ages that I cannot see what is the subtle error I have. At the least for now the logic work, it just it takes ram for nothing.

I'm sure right now my code is quite complex too but for now I do not mind much. If some code does cause issues I will change the structure after examinating the resulting .s files.


Last edited by Banshaku on Fri Jun 22, 2018 8:25 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 8:24 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 20679
Location: NE Indiana, USA (NTSC)
Banshaku wrote:
But my list of animation ends up in data:
Code:
const unsigned char* const *heroAnimList[5] = { standingAnim, ...,  runningAnim };

If the individual cels, sequences, and list of sequences are all const, you need three const in the declaration of the list of sequences. Does the following also end up in `DATA`?
Code:
const unsigned char* const *const heroAnimList[5] = { standingAnim, ...,  runningAnim };


Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 8:29 am 
Offline
User avatar

Joined: Mon Jan 03, 2005 10:36 am
Posts: 3132
Location: Tampere, Finland
tepples wrote:
Banshaku wrote:
But my list of animation ends up in data:
Code:
const unsigned char* const *heroAnimList[5] = { standingAnim, ...,  runningAnim };

If the individual cels, sequences, and list of sequences are all const, you need three const in the declaration of the list of sequences. Does the following also end up in `DATA`?
Code:
const unsigned char* const *const heroAnimList[5] = { standingAnim, ...,  runningAnim };

I find it easiest to read these from right to left:

The 1st one: heroAnimList is a pointer to a const pointer to unsigned char that is const
The 2nd one: heroAnimList is a const pointer to a const pointer to unsigned char that is const

So in this case the 2nd one should get placed in RODATA.

_________________
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi


Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 8:34 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2008
Location: Fukuoka, Japan
tepples wrote:
If the individual cels, sequences, and list of sequences are all const, you need three const in the declaration of the list of sequences. Does the following also end up in `DATA`?
Code:
const unsigned char* const *const heroAnimList[5] = { standingAnim, ...,  runningAnim };


Just tested it and it is now in rodata. I had a feeling that it was something simple but I never used that many const before and looked like it was too many of them. I was wrong.

Thank you Tepples!

Seems like the Zxibit meme where we heard that you like const, so we put const in your const so you can const :lol:


Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 8:40 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2008
Location: Fukuoka, Japan
thefox wrote:
I find it easiest to read these from right to left:

The 1st one: heroAnimList is a pointer to a const pointer to unsigned char that is const
The 2nd one: heroAnimList is a const pointer to a const pointer to unsigned char that is const

So in this case the 2nd one should get placed in RODATA.


Read that way it makes it quite easy to understand. I didn't use much C in more than 10 years so I'm either rusty or didn't understand much at the time about const (I was more active around 93 during college but I don't remember much about talking about const with Turbo C at the time).


Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 10:14 am 
Offline

Joined: Sun Apr 13, 2008 11:12 am
Posts: 7676
Location: Seattle
You might find the "cdecl" program useful.
Code:
cdecl> explain const unsigned char* const *const heroAnimList[5]
declare heroAnimList as array 5 of const pointer to const pointer to const unsigned char


Top
 Profile  
 
PostPosted: Fri Jun 22, 2018 7:20 pm 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2008
Location: Fukuoka, Japan
@lidnariq

What a coincidence, I did found that software yesterday when I was trying to find information about arrays of arrays of pointers. I don't know how to use it yet and at first tried to test with "declare", which is like writing English. I will try it with "explain" next time. Thank you for the tip!


Top
 Profile  
 
PostPosted: Sat Jun 23, 2018 4:06 am 
Offline
User avatar

Joined: Sat Sep 07, 2013 2:59 pm
Posts: 1708
Banshaku wrote:
I had a feeling that it was something simple but I never used that many const before and looked like it was too many of them.

Well, it's only logical:
A constant array needs one const.
An array of an array needs two consts.
And an array of an array of an array needs three consts.

One const for each * or [].

_________________
Available now: My game "City Trouble".
Website: https://megacatstudios.com/products/city-trouble
Trailer: https://youtu.be/IYXpP59qSxA
Gameplay: https://youtu.be/Eee0yurkIW4
German Retro Gamer article: http://i67.tinypic.com/345o108.jpg


Top
 Profile  
 
PostPosted: Sat Jun 23, 2018 9:41 am 
Offline
User avatar

Joined: Tue Jun 24, 2008 8:38 pm
Posts: 2008
Location: Fukuoka, Japan
Yes, put that way it is logical. I guess I didn't visualize it as 3 arrays at first. I'm so used to language with their own memory management at work that pointers are not something common for me to use. I think I will need to review a little bit on the subject and try to work on that when I'm not exhausted (easier to find bugs this way ^^;;).


Top
 Profile  
 
PostPosted: Sat Jun 23, 2018 10:50 am 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 6898
Location: Canada
DRW wrote:
One const for each * or [].

[] is a bit different than * in this respect.


A * takes whatever type was on the left, and replaces it with a pointer to that type. That pointer itself is a 2 byte (or 4/8 byte) variable that stores an address, and that stored address can be modified if it's not const. The syntax allows you to put const immediately after the * to specify that it should not be modified.


A [] builds an array of whatever type was on the left. There's no place in the syntax to specify const like there is with *, because there is no pointer here. The array type is like all other variables; it can't be moved in the same way that "int a" can't be moved.

The difference might make some sense with an appeal to the 6502: we can always use absolute addressing to access variables or arrays (with indexing), but pointers always require indirect addressing.

You'll find if you try to assign a [] to another [] it will tell you that it's an invalid lvalue which is what the language spec calls variables, sort of. Array types are a non-modifiable lvalue, so you can't assign directly to them, except as part of the initial definition. (It was historically decided in C that arrays should not be assigned to, because that would really mean to copy the whole array, which is usually inefficient. So, they made arrays a special case, and the spec has to mention that over and over. When structs were added later they decided it was okay to assign to structs, though.. the language might seem inconsistent in this way. The implicit conversion of arrays to pointers makes this slightly more confusing too.)


There's an exception here, though. If the [] type is a parameter to a function, it implicitly behaves like a non-const pointer instead (modifiable lvalue). The language is actually missing a way to specify this as const. This conversion to a pointer type is forced by the location of the passed array being unknown at compile time. If you need const here, though, you can simply use a const * type instead, as arrays can always implicitly convert to pointers anyway. (So: a parameter [] is really a pointer with a syntax that unfortunately overrides the true array.)

(The importance of const on a parameter is minor, though. The consequences of reassigning it are local to that function; it won't make a difference in DATA vs RODATA etc. like it would with a variable's definition.)


Edit: I found this, which might explain it better: http://c-faq.com/aryptr/index.html


† I think C99 might have added the option to put const inside the []? Not sure.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: TmEE and 3 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group