Monthly Target: $400 Donations: $79
 19% 

[TUT] The Preprocessor (#if, #include, #pragma, etc.)


Post New Thread Reply   
 
Thread Tools Display Modes
Author Message
Hawk552
Veteran Member
Join Date: Aug 2005
Old 11-02-2006 , 22:01   [TUT] The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #1

This article assumes you have intermediate knowledge of Pawn and its implementation in AMXX, and that you have advanced knowledge of optimization as well as what a compiled plugin looks like (opcodes and various reasons for optimization). It is still possible to read and understand this without this knowledge, but it is not recommended and certain parts may seem strange / unfamiliar.

The preprocessor is a part of the compiler specifically designed to process commands/routines before they are actually compiled or interpreted. It is generally used to make things easier for modification, add readability, and speed up operations.

The most basic operation involved in the Pawn precompiler is the #include directive. An example of this, that hopefully you've seen before, is:

Code:
#include <amxmodx>

What this is literally doing is replacing the directive with the contents of amxmodx.inc. Instead of having to copy out all the constants and natives each time you want to make a script, the preprocessor does the work for you and allows you to include header files quickly and easily. Another less common way to "include" a header file is:

Code:
#include "amxmodx.inc"

Notice you include the extension for this - this means you can also include .sma files or any other file format (as long as the contents make sense to the compiler).

The preprocessor, albeit much more limited than most compilers out there, is capable of much more, however. It can be used to easily change settings in a plugin without needing a cvar. This is particularly useful for a variable of n size, allowing you to do something like this:

Code:
#include <amxmodx> #define VAR_SIZE 33 new g_Variable[VAR_SIZE] public plugin_init() {     copy(g_Variable,VAR_SIZE - 1,"test") }

Ignoring the fact that we have sizeof (another preprocessor directive that will be covered later on), this makes for easy manipulation of variables.

This feature is often misused however, like so:

Code:
#include <amxmodx> #define AUTHOR "Hawk552" public plugin_init()     register_plugin("whatever","1.0",AUTHOR) public client_putinserver(id)     client_print(0,print_chat,"This server is running something made by %s.",AUTHOR)

Why is this a misuse? Well, if you know about optimization, you would know that every instance of AUTHOR is literally replaced by the definition (in this case, "Hawk552").

Normally, this isn't bad, but the Pawn compiler sucks at optimization. Instead of combining all of these duplicates into one variable, it instead makes 1 for each time you actually use the definition. If you only use it in register_plugin (like most people do), then this is no faster (and probably better, since global variables are stored even after needed) than a global variable. The other problem is that it is literally created each time it's needed, meaning the memory must be freed and set to whatever the definition is.

Again, there are some things acceptable. For instance, only using a define for integers (as in, one cell) is usually not too bad.

What I usually do to get around this, however, is the following:

Code:
#define AUTHOR "Hawk552" // ... later on ... new g_Author[] = AUTHOR

Not only does this eliminate the optimization problem, it also eliminates the chance that a user might do something stupid like change AUTHOR to 3, which would throw off the entire plugin.

The next important preprocessor macro is pragma. This directive is used mainly for things that the AMXX core (or any other core running a Pawn plugin) must know before the plugin is loaded.

The pragma directive can be used for many things in AMXX - for instance, increasing the amount of memory (16kb by default) allocated to each plugin. If you want 128kb, for example, you can run this macro somewhere in your plugin:

Code:
#pragma dynamic 32768

This is not particularly useful for most plugins, but is generally needed for plugins that use a lot of memory, such as WC3, Superhero Mod, or any mod of that calibre.

pragma is also used for many other operations, such as semicolon (forces the compiler to use semicolons to close lines, use #pragma semicolon 1), libraries/classes (#pragma library "library", #pragma reqlib "mylib", #pragma reqclass "myclass", etc. - for a demonstration of these, look at the top of the module header files).

The next important preprocessor macro is #if (which will have #else and #endif explained with it). #if allows you to check defined variables, and perform actions and add or remove code depending on an environment.

A prime example of this is checking the AMXX version and acting correspondingly, like so:

Code:
// or whenever query_client_cvar was introduced #if AMXX_VERSION_NUM < 160 native query_client_cvar ( id, const cvar[], const resultFunc[], paramlen=0, const params[]"") #endif

Another way of checking this, is like so:

Code:
#if !defined query_client_cvar native query_client_cvar ( id, const cvar[], const resultFunc[], paramlen=0, const params[]"") #endif

NOTE: If you try to run query_client_cvar on a version of AMXX lower than 1.60, it WILL NOT FUNCTION. This simply adds the native, allowing the compiler to compile it properly even if it is a version earlier than 1.60.

As you can see, the preprocessor is quite powerful this way. You can also use #else, in the structure "#if / #else / #endif".

The final important preprocessor macro (in my opinion) is sizeof. Most people seem to think this is actually a function, for some reason, and use it like "sizeof(string)". This usage is not incorrect, it just, to be blunt, makes you look like an idiot.

sizeof is useful for strings or variable dimension arrays. The most prime example is like so:

Code:
new var[] = "zomg" copy(var,sizeof var - 1,"gomz")

The size of var can change, but the sizeof will keep up with it anyway. A common misconception is to use:

Code:
copy(var,sizeof var,"gomz")

This is totally incorrect and can lead to buffer overflows. The reason is that sizeof returns the size of the entire array, not the size that would make it format perfectly (or rather 1 cell less than it really is). This means that, if the string copied is longer than the buffer size, the 0 (null terminator) will be copied onto a variable outside of the declared bounds.

There are many, many more preprocessor macros (such as #endinput, #error, #assert), but I will not go into them as they are not very important, and it's not really worth pushing this farther than it is already.

Like always, and questions or comments can be posted about.
__________________
Hawk552 is offline
Send a message via AIM to Hawk552
Nostrodamous
BANNED
Join Date: Oct 2006
Old 11-02-2006 , 22:53   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #2

gj nice tutorial hawk . another one ! bravo ! anyways you left out some pragmas , and if you want to look them up(im talking to the readers) heres a link to the pawn documentation you can find some more pragmas , there listed under statments


Last edited by Nostrodamous; 11-03-2006 at 02:42.
Nostrodamous is offline
Old 11-02-2006, 22:59
SweatyBanana
This message has been deleted by Brad. Reason: off-topic
Old 11-02-2006, 23:04
Nostrodamous
This message has been deleted by Brad. Reason: off-topic
Old 11-02-2006, 23:38
SweatyBanana
This message has been deleted by Brad. Reason: off-topic
Old 11-03-2006, 02:26
Nostrodamous
This message has been deleted by Brad. Reason: off-topic
Old 11-03-2006, 04:13
Greenberet
This message has been deleted by Greenberet.
VEN
Veteran Member
Join Date: Jan 2005
Old 11-03-2006 , 06:20   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #3

Corrections:

Quote:
sizeof (another preprocessor directive
sizeof isn't a preprocessor directive, it's a pawn operator

Quote:
The next important preprocessor macro is pragma
The pragma isn't a preprocessor macro, it's a preprocessor directive. The macro is a substitution block which can be created with define directive.

Last edited by VEN; 11-03-2006 at 06:29.
VEN is offline
Hawk552
Veteran Member
Join Date: Aug 2005
Old 11-03-2006 , 09:29   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #4

Quote:
Originally Posted by VEN View Post
Corrections:

sizeof isn't a preprocessor directive, it's a pawn operator

The pragma isn't a preprocessor macro, it's a preprocessor directive. The macro is a substitution block which can be created with define directive.
My bad, I'll fix those when I get home.
__________________
Hawk552 is offline
Send a message via AIM to Hawk552
PM
hello, i am pm
Join Date: Jan 2004
Location: Canalization
Old 11-03-2006 , 09:52   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #5

It's also very interesting that you can do FANCY stuff using function-like macros

Code:
#define MIN(%1,%2) ( ((%1) < (%2)) ? (%1) : (%2))


MIN(5, 6) evaluates to:

( ( (5) < (6) ) ? (5) : (6) )
(damn, I can't see whether I've got enough parenthesis even with those spaces!!)
Thus evaluating to 5.

Of course, HARDCORE C Programmers notice immediately: THIS IS TEH SHIT because if you pass ++i, ++i will appear twice in the preprocessor output, thus i will be incremented twice if one of the code paths is taken and only once if the other one is taken. That's why you might want to always mark function-like preprocessor macro using CAPS LOCK (or by holding shift while writing the macro name).

Greetings,
PM
__________________
hello, i am pm
PM is offline
Hawk552
Veteran Member
Join Date: Aug 2005
Old 11-03-2006 , 10:06   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #6

Hi PM!

Thanks for that explanation, I heard that can happen before, but I wasn't sure why.
__________________
Hawk552 is offline
Send a message via AIM to Hawk552
Rolnaaba
Veteran Member
Join Date: May 2006
Old 11-03-2006 , 10:12   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #7

nice hawk552 very informative, quick question tho.

if you use
Code:
#pragma semicolon 1
will thAt setting be saved in compiler and continue to check for semicolon on all plugins created using the compiler or will it stand only for the plugin its in and temporarily search in just that plugin? I think the later is correct but not sure
__________________
DO NOT PM me about avp mod.
Rolnaaba is offline
Hawk552
Veteran Member
Join Date: Aug 2005
Old 11-03-2006 , 10:19   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #8

Quote:
Originally Posted by Rolnaaba View Post
nice hawk552 very informative, quick question tho.


if you useCode:
#pragma semicolon 1


will thAt setting be saved in compiler and continue to check for semicolon on all plugins created using the compiler or will it stand only for the plugin its in and temporarily search in just that plugin? I think the later is correct but not sure
No, just that plugin.

It's totally useless though, there's no real point in using it unless you really like closing your lines with semicolons and want to be sure you did for that plugin. It's also good to figure out where to put them, since there are some places that you would have to that most people don't know (i.e. in a do-while loop, the while statement should be closed with a semicolon, something most people don't know).
__________________
Hawk552 is offline
Send a message via AIM to Hawk552
Nostrodamous
BANNED
Join Date: Oct 2006
Old 11-03-2006 , 10:24   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #9

yea its only executed on the plugin its included on in the pre-processor section . and its only usefull if you want to get used to using semi-colons for C ++.
Nostrodamous is offline
Zenith77
Veteran Member
Join Date: Aug 2005
Location: A boat.
Old 11-03-2006 , 12:31   Re: The Preprocessor (#if, #include, #pragma, etc.)
Reply With Quote #10

Quote:
Originally Posted by Nostrodamous View Post
yea its only executed on the plugin its included on in the pre-processor section . and its only usefull if you want to get used to using semi-colons for C ++.
  1. You just restated the same exact thing hawk said
  2. semi-colons aren't just used in C++.
__________________
Quote:
Originally Posted by phorelyph View Post
your retatred
Zenith77 is offline
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 05:41.


Powered by vBulletin®
Copyright ©2000 - 2015, vBulletin Solutions, Inc.
Theme made by Freecode