This page has been automatically translated using the Google Translate API services. We are working on improving texts. Thank you for your understanding and patience.
Most programming languages contain good parts and bad parts. I discovered that I could be a better programmer by using only the good parts and avoiding the bad parts. After all, how can you build something good out of bad parts? Douglas Crockford - JavaScript: The Good Parts.
Programming fast, reducing the probability of error, ensuring portability and generating optimized binaries have been the main purposes of NAppGUI since its inception and that includes a revision of the C language itself. A subset of ANSI-C90 with fixed-size integers <stdint.h>, a feature introduced in C99, has been used as a base language. We recommend that applications based on this SDK follow the same philosophy. Going into more detail, the objectives pursued have been these:
Maximum portability: Even on already outdated compilers like MSVC 8.0 (Visual Studio 2005) or GCC 4.2 (Xcode 3). The latest language features may not be available on platforms where you must port your code (think embedded devices). You also ensure that such code will be compatible with future versions of major compilers.
Focus attention: On the "what" and not on the "how". There are times when we make the simple complicated just to justify the use of that new "cool" feature. It is also possible that you are a "hip" addict, which will force you to "modernize" the code to adapt it to a new version of the standard. Focus on solving the problem at hand and, if you can, spend more time on lowering the asymptotic complexity of your solution. NAppGUI will make sure that your applications work wherever they are needed.
Avoid irrelevant features: Like C11's multi-threading support (<threads.h>). This is solved with system calls. See Threads.
Fast compilation: Certain C constructs are nothing more than a kind of "portable assembler", which the compiler can interpret and translate incredibly efficiently.
Small and fast binaries: Derived from the previous one, the generated code will require few assembly statements and will be very easy for the compiler to optimize.
Evidently, this is not the place to learn C nor is it our intention. The core of the language is small and easy to remember, but programming well requires years of practice. What we will do here is show the minimum expression of the language that we use daily. In short, these are our standards.
1. Basic types
Void:void.
Boolean:bool_t. 8-bit type with only two possible values TRUE (1) and FALSE (0).
Integers:uint8_t, uint16_t, uint32_t, uint64_t, int8_t, int16_t, int32_t, int64_t. Fixed-size integers were introduced in C99 by <stdint.h>. We consider it an advantage to know that our variables will have the same size in all systems. The use of int, long, short or unsigned is prohibited, with the sole exception of the comparison functions .
Floating point:real32_t, real64_t. float and double are not used for consistency with integer types.
Character:char_t (8 bits). The UTF8 representation is used "de facto" throughout the SDK, so random access to elements of a string is prohibited, since it is a variable-length encoding. Functions included in Unicode or Strings must be used to manipulate arrays of characters. The types wchar_t, char16_t, char32_t are not used (or recommended). However, if you have wide-char strings you will need to convert them to UTF8 before using them in any NAppGUI functions.
Using UTF8 strings
/* Error! */constchar_t *mystr = "Ramón tiene un camión";
while (mystr[i] != '\0')
{
if (mystr[i] == 'ó')
{
/* Do something */
}
else
{
i += 1;
}
}
/* Correct! */constchar_t *it = mystr;
uint32_t cp = unicode_to_u32(it, ekUTF8);
while (cp != '\0')
{
if (cp == 'ó')
{
/* Do something */
}
else
{
it = unicode_next(it, ekUTF8);
cp = unicode_to_u32(it, ekUTF8);
}
}
/* Avoid using wchar_t constants (when possible).
wchar_t uses UTF16 encoding */const wchar_t *mywstr = L"Ramón tiene un camión";
char_t mystr[512];
unicode_convers((constchar_t*)mywstr, mystr, ekUTF16, ekUTF8, sizeof(mystr));
/* This is a NAppGUI function (UTF8-Encoding) */label_text(label, mystr);
Enumerated: Their main task is to manage the specialization and they will be evaluated exclusively within a switch. It is forbidden to assign random values to the elements of an enum, except 1 to the first one. Consider 0 as not initialized and ENUM_MAX(align_t) as invalid.
In general, structure definitions will not be public and will remain hidden in the *.c. This means that automatic variables cannot be declared in the Stack Segment and will only be accessible by functions that accept opaque dynamic objects.
/* Layout definition is hidden
We do not know the content of Layout */Layout layout; /* Compiler error! */
Normally, all dynamic objects will have a destroy function. If it does not exist, it is because said object only makes sense as part of another object. For example, there is no layout_destroy() or panel_destroy(), but there is window_destroy which will destroy the entire hierarchy of panels and associated layouts to the window.
3. Control
if/else. They always open a {...} block, unless ALL paths consist of a single statement. Using functions as arguments to if/else is generally avoided with the exception of pure functions.
Use of if/else
if (x == 1)
i_do_something(j);
else
i_do_nothing();
if (x == 1)
{
j += 2;
i_do_something(j);
}
else
{
i_do_nothing();
}
if (bmath_sqrtf(sqlen) < 20.5f)
i_do_something(j);
while. Nothing to comment.
do/while. Not allowed. Use for or while.
for. For infinite loops, use for(;;) instead of while(TRUE), as it avoids warnings in some compilers. Since there are ANSI-C based compilers, such as MSVC++ 8.0, we do not use variable declarations inside the for(), a feature that was introduced in C99.
Use of for
/* Infinite loop */for(;;)
{
...
}
/* Will not work in some compilers (not used) */for (uint32_t i = 0; i < 1024; ++i)
{
...
}
/* Ok */uint32_t i = 0;
...
for (i = 0; i < 1024; ++i)
{
...
}
switch. It is only used to discriminate between the values of an enum. Any other data type will NEVER be evaluated in a switch nor will an enum be discriminated within an if/else construct. The compiler can drastically optimize the performance of a build with these features.
Variables are declared at the beginning of a block and cannot be mixed with statements, unless we open a new scope. Declarations mixed with statements is a C++ feature added to the C99 standard, but not all C compilers support it. Yes, it is allowed to initialize a variable by calling a function.
Apart from the advantages of using pointer arithmetic when implementing certain algorithms, in NAppGUI pointers are used essentially in two situations:
Passing parameters to a function, when said parameter is not a basic type.
Handling opaque objects. Where the definition of the struct is not available and therefore the only way to communicate with the object is through functions that accept a pointer to it.
Special mention should be made of the function pointers that are widely used in C, but less so in C++ as the language hides them inside vtables. However, a strategically placed function pointer can make it easier for us to add specialized functionality to existing objects, without having to adopt a more purist object-oriented design.
Our standards make heavy use of the preprocessor, especially for type checking at compile time. This helps to detect errors in the code before running the program (static analysis), as opposed to the C++ RTTI that does it once it is running (dynamic analysis).
Using the preprocessor to check types.
#definearrst_destroy(array, func_remove, type)\
((void)((array) == (ArrSt(type)**)(array)),\
FUNC_CHECK_REMOVE(func_remove, type),\
array_destroy_imp((Array**)(array), (FPtr_remove)func_remove, (constchar_t*)(ARRST#type)))
ArrSt(Product) *products = arrst_create(Product);
...
staticvoid i_remove_product(Product *product)
{
}
...
/* 'products' and 'i_remove_product' will be checked at compile time */arrst_destroy(&products, i_remove_product, Product);
Dynamic typing is not necessarily good. You get static errors at runtime, which really should be catchable at compile time. Rob Pike.
8. Comments
In general, the use of comments will be reduced as much as possible. A comment will be placed at the beginning of each file as a general description. We also use a comment line as a separator when implementing functions.
stream.c
/* Data streams. Manage connection-oriented communication */#include "stream.h"
#include "stream.inl"
#include "bfile.h"
#include "bmem.h"
...
/*---------------------------------------------------------------------------*/staticvoid i_func1(void)
{
/* Do something */
}
/*---------------------------------------------------------------------------*/staticvoid i_func2(void)
{
/* Do something */
}
C++ comments // Comment... are NOT allowed, as they generate warnings in certain gcc -std=gnu90 compilers.
Another aspect that is totally prohibited is the inclusion of documentation blocks within the source code, not even in the headers themselves. NAppGUI uses ndoc for documentation tasks, a utility that allows you to create html/pdf documents enriched with images, cross-references, examples, etc. and that uses its own files totally separated from the code. Another added advantage is the cleanliness of the *.h headers of all the modules, where it is very easy to locate what we are looking for.
Documentation blocks are NOT allowed.
/* Forbidden, non used *//*! Gets the area of the polygon.
\param pol The polygon.
\return The area.
*/real32_tpol2d_areaf(constPol2Dd *pol);
All comments in NAppGUI are made in English language.
9. Input/Output
Input/output is not part of the C language as such. As the language spread in the mid-1970s, a number of useful routines were grouped together into what became the Standard C Library. NAppGUI encapsulates all its functionality in Sewer, Osbs or Core generally implementing it as much more direct and efficient calls to the operating system.
Use of safe I/O functions.
/* Do not use cstdlib in applications */#include <stdio.h>
FILE *fp = fopen("/tmp/test.txt", "w+");
fprintf(fp, "This is testing for fprintf...\n");
fclose(fp);
/* Use NAppGUI functions */#include "stream.h"
Stream *stm = stm_to_file("/tmp/test.txt", NULL);
stm_printf(stm, "This is testing for stm_printf...\n");
stm_close(&stm);
Use of the Standard C Library is not recommended. Look for the equivalent function in Sewer, Osbs, or Core.
10. Mathematical algorithms
NAppGUI uses C++ templates to implement any function or mathematical algorithm. With this it is possible to offer float and double versions in an elegant way and with easy maintenance. The templates are hidden and not exposed in the API, so that their use remains ANSI-C90 compliant. For more information Math templates.
NAppGUI makes internal use of C++98 template<> to implement everything related to mathematical calculation.