Learning C on RISC-OS
Pages: 1 2
Tomas (2352) 8 posts |
Hello to all, I’m a newbie staring to learn C. Since I have a lot of experience in programming in the RISC-OS environmenet (BASIC, assembler, WIMP programs, modules etc.) I decided to give it a go and install GCC on my VRPC and RPi. Sofar so good. I have written my first silly program and I want to take it a bit further ;-) Like calling a SWI (SVC nowadays). OSLib looked promissing, so I wrote the following try-out:
After geting all my silly mistakes out, it works as expected: the program scans the keyboard and if a key is pressed, it prints the internal Risc-os keycode. To exit press ‘A’ (code 65). Having studied various libraries, I still can’t get my head around how a SWI is actually called. I see a lot of definitions of variables, structures, pointers and (empty?) functions, but I just don’t understand how in the end a C program raises a SWI…. Is _swi(x) or __swi a part of C? I probably miss basic C knowledge & experience, but I’m terrible confused and I just want to know how things work, instead of using numerous libraries without having a clue what is happening inside. What do I need to do if I were to skip using libraries and make above program work? I hope someone can shed some light in my darkness ;-) Thank you in advance. Tomas |
Rick Murray (539) 13840 posts |
Good luck! Coming from assembler / BASIC, I had a lot of trouble with C at first (especially its inconsistencies!) but one day my mind just clicked and I was like “oh, I see, it works like this”. Structures? Awesome.
No, a SWI is still a SWI. Probably safer to stick with “SWI” within RISC OS.
BEFORE I BEGIN… You call a function. It may call other functions, but eventually you will be talking to a piece of assembler code that calls a SWI. For example, let’s look at turning the hourglass on and off and setting a percentage. Pure C the lame way:
This can be better written using _swi, like this:
Looks quite similar, but imagine more complex calls to _kernel_swi that would require all the registers to be set up first, while _swi is varadic so you can pass the values to the command. Now here is how to roll our own:
That’s the C code.
So, in summary – you can either call a SWI directly from C using the library calls That said – while my preferred method is assembler code calling SWIs directly, it has been suggested that swi()/swix() is the fastest way, see the second half of this post and onwards from this post.
Shared C Lib.
Refer to the above and apply accordingly. ;-) Hope this helps. |
Malcolm Hussain-Gambles (1596) 811 posts |
Indirected pointers? pffft! |
Steve Pampling (1551) 8170 posts |
In support of the concept of sensible recommendations – the heyrick set of pages contains stuff good enough to plagiarise1. There are also decent RISC OS related C programming resources “C from the top” and “C for yourself” spring to mind. C the wimp probably includes more SWI use. 1 I came across a site today2 that contains, word for word, the same content. We all know who produced the original. The copy stands out for having the content in MS Word format :) 2 This morning, before work as the web filtering on the normal link3 blocks access to “Entertainment” sites like www.heyrick.co.uk. It being classed as entertainment shows Sophos are techie through and through :) 3 I select my connections according to need. |
Jon Abbott (1421) 2651 posts |
Have you seen the source code for them! When you see labels like “swi_beyond_a_joke” you just know it’s not going to be good, there’s a lot of code just to cover R4-R9. _kernel_swi probably isn’t much slower as it’s a lot shorter (~10 instructions), although does need the registers setting up before the call. Your embedded ASM method would be the quickest method. |
Tomas (2352) 8 posts |
Hi again, @Rick Thanks for your extensive explanations. I’m going to play around before getting back with more questions & confusion ;-) @Steve I already found the pages on learning C, thanks! @Jon That’s an impressive piece of code compared to SWI Blahblah & MOV PC, R14 :-) |
Rick Murray (539) 13840 posts |
Gee, thanks! (^_^)
Already? Damn, that was quick. URL?
Word? Yuck!
Pffft! <blows raspberry in direction of Sophos> Maybe I should stop writing random musings and instead post lots of “unboxing” videos. Your filter blocks “entertainment”? That’s harsh. What kind of geek doesn’t drop by Dilbert and xkcd once in a while? |
Steve Pampling (1551) 8170 posts |
Start with this: greatflash.co.uk/index.php?action=dlattach;topic=69.0;attach=131
Harsh? The main link from site is N31 with a nominal 100Mb/s true bandwidth is 88Mb with 2Mb reserved for management and 10Mb for IP voice (whether you use it, at extra cost, or not). If I need the connection I switch to the next port on the wall (left or right) which could be a basic 20Mb ADSL network or the 30Mb on 100Mb fibre bearer symmetric link. To access the link to the Uni I’d have to go next door in to the switch room and move one of my lines.
No idea, I’d rather stick pins in my eye. 1 Lengthy explanation. |
Jeff Doggett (257) 234 posts |
The \r isn’t required in C, the printf library will add it automatically for you when it processes the \n. |
Rick Murray (539) 13840 posts |
Oh, right. It’s the old stuff. Yeah, I’ve seen it copied a fair few times. Came across one that was annotated in Chinese which amused me as I’d mention “PC” and there would be some squiggles afterwards that Babelfish informed me meant “position of liveliness” and other comical translations. Not the Google copes so well with Asian languages – trying to read Japanese wiki pages that way is a bit of a mind screw.
That what ARMwiki is intended to be. Not an associated resource, but a replacement for the very outdated 26 bit stuff.
Wha? – wait… You actually do work? The BOFH will be disappointed.
That makes two of us. The point being, I’d classify it as entertainment … err … in the same way that “my fat dead lesbian gypsy grandmother’s wedding’s tortured puppy” (60mins long, showing tonight on BBC THREE at 7pm, 8pm, 9pm, 10pm, 11pm, and midnight) is supposed to be entertainment.
If I ever care about cricket (and I don’t since the Filipina Southern Region Independent Girl’s School could probably beat the current English team if the girls were blindfolded, drugged, and the team was comprised of twelve year olds who didn’t even know how to play cricket), I just ask mom. |
Clive Semmens (2335) 3276 posts |
I’ve not tried Japanese, but I have Vietnamese friends. Google Vietnamese→English is good for a laugh, but sadly not much else. |
Steve Pampling (1551) 8170 posts |
Shhh. |
Tomas (2352) 8 posts |
After re-reading what has been said here and playing around with some simple test programs (finally) the penny dropped in place (as we say in Dutch ;-) I realised that header files don’t contain the code, but, as the name implies, only definitions for functions and declarations. My first idea was that the header files would contain the library C-code that would be included in your programs. Now I realised that this code is invisibly contained in the object files that are linked with my programs…. Better late then never ;-) Since my knowledge of C at this stage is so superficial, I was confused by what I saw in the header files. But one thing for me was sure: To call a SWI you simply had to leave the C language to get into the OS. But where ever I looked in the header files, I could not find a sign of that…. But back to calling a SWI, I guess that I like the _swi() method more then _kernel_swi(). Being someone who likes to know how things work instead of relying on ‘unknown libraries’, I can also see the charm of writing your own little pieces of ARM-code veneer to make the SWI calls. I have to admitt that I am a assembler fan anyway. I have spend the last years programming a lot of PIC microcontrollers and doing everything in assembly. But ‘alas’, also in the world of microcontrollers everything is getting bigger, faster and more powerful. Power that is best tamed with C programs, so they say… I did some try-outs with the UnixLibrary. I read that the UnixLib is not (yet) a shared thing as the well know RiscOS SharedClibrary. Are there any other pro’s or cons for using one or the other? Thanks again for your support. If all goes well, I’ll be making an WIMP application for a custom made datalogger for the Raspberry Pi. Greetings, Tom |
Theo Markettos (89) 919 posts |
A few suggestions. With C, learn to embrace libraries. They’re your friend. Somebody has already written code so you don’t have to, and they even maintain it for you. Learn to realise that absolute control isn’t always required if you can get the job done. If you have the source to the library, you can always go in and see how it works (and change it maybe) if you must, but it’s not compulsory. In other languages libraries are so painful that you end up writing everything yourself – you can do that, but you’ll get more done if you try not to worry about it. UnixLib is useful if you have a program or library with a POSIX API. It also handles some things like Unicode that the SharedCLibrary does not. It’s arguably less useful if you’re writing a fully-native program, but it’ll be necessary if you want to pull in something like libssl that needs POSIX functions. Embrace structures. There’s really no need for this block%!42 stuff that BASIC forces you to do. If you’re writing a cross-platform program, don’t assume anything about the layout of structures in memory. Try to avoid embedded assembler if you can – it won’t get type-checked, and assembler has caused numerous headaches in the past (eg StrongARM/32-bit compatibility, unaligned loads) that would have been fixed with a simple recompile if it were C code. Don’t over-optimise. The compiler is probably better at it than you. While _swi is quicker than _kernel_swi, OSLib has a useful advantage – the values are type-checked so you don’t end up passing a window handle as an icon handle or an integer as a string. That’s all too easy to do if you end up out-by-one with your commas. Finally, there are higher-level languages than C. Sometimes they are useful. |
Tomas (2352) 8 posts |
@Theo Thanks for a bag full of good advice ;-) After looking at the various libraries I think I’m gonna settle for gcc & OSLib. I enjoy the journey sofar, although things can be a bit overwhelming at first. |
Rick Murray (539) 13840 posts |
To expand upon what Theo has said – C in itself is a very basic language that does very little. It can’t even stick two strings together and display them to the user. Where C is very powerful is the library concept – there’s a clue in the names – DeskLib, SharedCLib, OSLib… Couple this with how most well-constructed libraries are assembled by a librarian program so that only the functions actually used are linked into the final executable (instead of the entire library), it is a highly flexible system. C is good for old-hands at assembler – it allows you to do a number of things that make sense to an assembler programmer without the shackles imposed by some other languages (Pascal, I’m looking at you). You can do cool things like use the “union” structure to treat something as a series of integers or as a series of bytes at the same time (poll blocks use this sort of thing extensively). You can take an arbitrary bit of memory and point to it and say “treat this as such-and-such a struct”. But, it comes at a price. You can create a null pointer, allocate 1024 bytes and assign the pointer to point to that bit of memory, and then write 100K of data to that location (assuming you don’t trash your own stack first). Without add-ons, C will not sanitise your array accesses. As Theo says – embrace structures. I have in my MIDI module a direct port from a prototype written in BASIC of a function to scan the USB devices. It works, but it is the most miserable horrible code I have ever written. When I have time, I’m going to tear it all out and write it again using proper structs instead of attempting to reproduce an exact replica of the @ Theo – why won’t embedded assembler get type checked? I mean, if you set the function in the header to @ Theo, again:
I partially disagree. I find it a lot less hassle to create snippets of assembler code to do things that are more trouble than its worth in C (you can write a Wimp program using On the subject of optimisation, it might be worth reading this for a laugh or two: http://www.heyrick.co.uk/assembler/exa9b.html Note, also, that the compiler can be given command line options to favour small code or fast code.1 But for the compiler to do its job correctly, you have to help it. That said – the world will definitely prefer slower working code than cleverly optimised code that is somewhere between “quirky” and “broken”. Stay away from the comma operator. It confuses things too easily. Don’t try to be clever with pointers, if you ever plan to release your code to others, they would definitely appreciate something that they can read. 1 It tickles me that the usual option on x86 compilers for “all the optimisations all at once” is |
Rick Murray (539) 13840 posts |
Oh, and…
Once you are more familiar with the language and how it works, “some test software written in C worked within a couple of hours”. (^_^) |
Steve Fryatt (216) 2105 posts |
You’d use something like OSLib, surely? :-) |
Tomas (2352) 8 posts |
I recently decided on using OSLib, but do I read between the lines (@steve fryatt) that using OSLib is hardly better than using _swi() or _kernel_swi()? Or ? Since I’m in an absolute beginner’s stage I appreciate good advice on this. A good choice made from the start will hopefully pay off…. I’ll have to start some serious (WIMP)programming soon… So if there are better options, I’d like to know. I had a look at DrWimp, but after setting up a few things I was startled with a directory full with junk, of which I did not recognise 90% on how or what to use them for… So maybe that’s not for beginners ;-) DeskLib seemed to focus on the Wimp, but I had the idea it lacked on the standard stuff, so it would need to be used in conjunction with something else I guess. Again, correct me if I’m wrong. Thanks, Tom |
Rick Murray (539) 13840 posts |
What do you mean by the standard stuff? Most of my applications written in C use only DeskLib and the standard libraries. I have also made a (hopefully compete) port of v2.30 to 32bit… |
Rick Murray (539) 13840 posts |
(deleted, in car with patchy reception, phone sent the message twice) |
Chris Johnson (125) 825 posts |
I think Steve was saying the opposite, i.e. use oslib rather than _swi. It is typesafe and provides calls to essentially all SWIs, including a whole range of libraries, particularly the toolbox. If you use _swi or _kernel_swi then you will end up writing your own library for all the calls you make more than once. |
Rick Murray (539) 13840 posts |
And when you do that, you’ll soon realise that you really don’t need to provide all those parameters every time and indeed your routines can exhibit a little bit of intelligence. Et voilà, a library is born.
This is where DeskLib differs. The Wimp handling of DeskLib works on “events”. You assign functions to be called on specific events, and DeskLib deals with the nuts and bolts of the application. It is still quite low level due to how RISC OS works, think of it as a useful level between VisualBasic style abstraction and direct SWI calls. |
Chris Johnson (125) 825 posts |
The OP was talking about _swi etc. OslibSupport has a number of higher level libraries, including event, message, X exceptions and so on. The event library is fine for dealing with wimp and toolbox events. |
Steve Fryatt (216) 2105 posts |
Exactly: OSLib gives you full control over the SWIs, while making everything typesafe and much easier to understand. provides calls to essentially all SWIs I’m not sure that follows: even with events, you still need to call most of the same SWIs from the event handlers to make things happen. There are also event libraries out there which work with OSLib. There may be one shipped in OSLib’s support download1; otherwise NetSurf is built on one (which might be hard to extract as its low-level interface is a bit tangled), and my own SFLib contains one. I’m sure that there are many others, too — many developers just seem to write their own… I’d certainly support the idea of using one of the event libraries, however. Certain aspects of the way that RISC OS handles the Wimp (menus being a good example) are extremely messy. A well-written event dispatch library will make things a lot easier to understand and use, while still giving you full control of what is happening. 1 ETA: there is, as Chris’s post before mine confirms. |
Pages: 1 2