C programming practices for the Saturn

I've noticed these looking at other people's source, and I've tried looking them up but I actually couldn't find much useful. I have thought about maybe going to another more general programming board, but then maybe something here was specifically important for Saturn, so I just thought I'd post here.

1. Why do I see "(void*)" in front of values and returned data passed to and from system functions? (one example being the Saturn's slPrint.) What exactly is a (void*)[value]? I know that void = ...no value, and I would interpret (something)[value] as a value cast, but I'm not sure why you'd cast as a value as something that doesn't have a value. I see this in functions and also when setting registers.

2. Why do you use Static and Volatile flags? If I'm right, I believe that they allow for values/functions to be declared at fixed points in memory that do not change. But I do not understand the difference between the two. It would make sense, with the Saturn's limited memory, to put something at a distinct point in memory, but I do not understand how these flags 1) allow you to place something at a specific point (how exactly do you control where it stays?) and 2) when would you want to use the flags? A lot of the code in examples or libraries here (I'm running through the Elbesem code as we speak) uses the flags for some variables (like, for example, counters for a while() loop) and not elsewhere.

If anyone could give me some advice regarding that, I'd be very helpful.
 
Okay, I just figured out some distinction.

Static is when you want a variable or declaration to stay in the exact same location in memory. So, declaring a local variable as static means it will never move no matter how many times you call that function, and if you store a value in it, the value will remain even after the function's scope has ended. And, if objects are inherited from a base class with a static variable, all classes will use the exact same singular instance of that variable.

Volatile...is when you don't want the compiler to do anything to optimize the variable? Something about, for example, when setting to registers, you don't want the compiler to change anything. I guess that makes sense.

When exactly then, would you want to use these? Volatiles when assigning to memory? Though I'm new to this, there might be a way to point to a distinct location in the Saturn's memory map (heck, without question -- I'm just rusty on my pointers) so then you would declare such a pointer as Volatile, right?

Still no clue about the (void*) though. Does any of this sound right?
 
In C, it is illegal to assign pointers of incompatible types. Void pointers are defined as a generic pointer type, but you can't dereference them. As an example, take the function memset() which sets a block of memory to the specified byte value. If the function was declared as
Code:
memset(int *s, int c, size_t n)
you could only use it to fill arrays of integers, passing the address of an array of floats would be illegal and give a compiler failure. By declaring the function as
Code:
memset(void *s, int c, size_t n)
it can accept pointers of any type without compilation errors. But as I said, inside the function you cannot dereference the pointer without giving it a type (eg. ((char*)s)[n] = c). As a sidenote, before the C89 standard there was no void type, and char pointers were used instead. AFAIK that is still legal, but discouraged.

The volatile keyword is a hint to the compiler that the object may be modified in a way that the compiler can't detect. What the keyword actually does is not specified, but with most compiler implementations it will prevent some optimizations as you noted. Typical uses are accesses to hardware registers and shared variables in multitasking environments. Note that volatile by itself may not be enough as caches etc. may interfere.

In C, static is used for two things: to specify lifetime and visibility. Static variables declared inside functions have global lifetime, ie. the same as the program. They are initialized once, before the program starts and will keep their value between calls of the function.

Functions and global variables declared static are not visible outside the file they are declared. The can be freely accessed by other functions in the same file, but if you try to access them from another file you will get a compiler error. You can have other static functions and variables with the same name in other files without getting conflicts. In C++, static is additionally used to declare static member variables (which are shared between all class instances) and functions (functions of the class that can be called directly and that cannot access any private data).
 
Back
Top