In case where I use data that is stored "deep" inside structures I want a way to use a shorter name to refer to it to increase readability. Is there a way to do it without an assignment to a local variable or pointer (which aren't needed functionally).
Example:
int foo (struct1 *in_strct1, struct2 *in_strct2, struct3 *out_strct3)
// an exaggerated example for a function that calculates one of the zeroes of
// a quadratic equation, where the inputs and the output are hidden very deep
// inside the structures.
{
/*unnecessary assignment that aren't needed functionally, but without *
*them the code would be unreadable. */
double a = in_strct1->sublevel1.sublevel2.somearray[5].a;
double b = in_strct2->somearray[3].sublevel2.sublevel3.b;
double c = in_strct2->someotherarray[6].inside.even_deeper_inside.almost_there.c;
double *res = &out_strct3->a_very_long_corredor.behind_the_blue_door.under_the_table.inside_the_box.on_the_left.res;
//actual logic
*res = (-b+sqrt(pow(b,2)-4*a*c))/(2*a);
return 0;
}
You should always strive for readability, and your defining a, b, and c helps to attain that.
I wouldn't worry about any perceived overhead in doing that: a good compiler ought to optimise out a, b, and c. Check the output assembly if you have any doubts.
Writing const double a in place of double a etc. will help the compiler even more.
As Eugene points out in his comment, a #define could be used, though it does have scoping risks. An alternative is to create a pointer to it. The pointer is, effectively, an alias to the location.
Unfortunately, this does require an assignment... But short of an assignment I do not believe this is possible.
Using pointers to do this might make it impossible in some situations for some compilers to optimise them out, thus making performance worse than using normal variables. However for this specific example pointers would probably be optimisable in all cases I can think of.
In your case I recommend using local #defines within the function body and then #undef them again before the end of the function.
Something like...
int foo (struct1 *in_strct1, struct2 *in_strct2, struct3 *out_strct3)
{
#define a (in_strct1->sublevel1.sublevel2.somearray[5].a)
#define b (in_strct2->somearray[3].sublevel2.sublevel3.b)
#define c (in_strct2->someotherarray[6].inside.even_deeper_inside.almost_there.c)
#define res (out_strct3->a_very_long_corredor.behind_the_blue_door.under_the_table.inside_the_box.on_the_left.res)
//actual logic
res = (-b+sqrt(pow(b,2)-4*a*c))/(2*a);
return 0;
#undef a
#undef b
#undef c
}
A coding style presentation that I attended lately in office advocated that variables should NOT be assigned (to a default value) when they are defined. Instead, they should be assigned a default value just before their use.
So, something like
int a = 0;
should be frowned upon.
Obviously, an example of 'int' is simplistic but the same follows for other types also like pointers etc.
Further, it was also mentioned that the C99 compatible compilers now throw up a warning in the above mentioned case.
The above approach looks useful to me only for structures i.e. you memset them only before use. This would be efficient if the structure is used (or filled) only in an error leg.
For all other cases, I find defining and assigning to a default value a prudent exercise as I have encountered a lot of bugs because of un-initialized pointers both while writing and maintaining code. Further, I believe C++ via constructors also advocates the same approach i.e. define and assign.
I am wondering why(if) C99 standard does not like defining & assigning. Is their any considerable merit in doing what the coding style presentation advocated?
Usually I'd recommend initialising variables when they are defined if the value they should have is known, and leave variables uninitialised if the value isn't. Either way, put them as close to their use as scoping rules allow.
Instead, they should be assigned a default value just before their use.
Usually you shouldn't use a default value at all. In C99 you can mix code and declarations, so there's no point defining the variable before you assign a value to it. If you know the value it's supposed to take, then there is no point in having a default value.
Further, it was also mentioned that the C99 compatible compilers now throw up a warning in the above mentioned case.
Not for the case you show - you don't get a warning for having int x = 0;. I strongly suspect that someone got this mixed up. Compilers warn if you use a variable without assigning a value to it, and if you have:
... some code ...
int x;
if ( a )
x = 1;
else if ( b )
x = 2;
// oops, forgot the last case else x = 3;
return x * y;
then you will get a warning that x may be used without being initialised, at least with gcc.
You won't get a warning if you assign a value to x before the if, but it is irrelevant whether the assignment is done as an initialiser or as a separate statement.
Unless you have a particular reason to assign the value twice for two of the branches, there's no point assigning the default value to x first, as it stops the compiler warning you that you've covered every branch.
There's no such requirement (or even guideline that I'm aware of) in C99, nor does the compiler warn you about it. It's simply a matter of style.
As far as coding style is concerned, I think you took things too literally. For example, your statement is right in the following case...
int i = 0;
for (; i < n; i++)
do_something(i);
... or even in ...
int i = 1;
[some code follows here]
while (i < a)
do_something(i);
... but there are other cases that, in my mind, are better handled with an early "declare and assign". Consider structures constructed on the stack or various OOP constructs, like in:
struct foo {
int bar;
void *private;
};
int my_callback(struct foo *foo)
{
struct my_struct *my_struct = foo->private;
[do something with my_struct]
return 0;
}
Or like in (C99 struct initializers):
void do_something(int a, int b, int c)
{
struct foo foo = {
.a = a,
.b = b + 1,
.c = c / 2,
};
write_foo(&foo);
}
I sort of concur with the advice, even though I'm not altogether sure the standard says anything about it, and I very much doubt the bit about compiler warnings is true.
The thing is, modern compilers can and do detect the use of uninitialised variables. If you set your variables to default values at initialisation, you lose that detection. And default values can cause bugs too; certainly in the case of your example, int a = 0;. Who says 0 is an appropriate value for a?
In the 1990s, the advice would've been wrong. Nowadays, it's correct.
I find it highly useful to pre-assign some default data to variables so that i don't have to do (as many) null checks in code.
I have seen so many bugs due to uninitialized pointers that I always advocated to declare each variable with NULL_PTR and each primitivewith some invalid/default value.
Since I work on RTOS and high performance but low resource systems, it is possible that the compilers we use do not catch non-initialized usage. Though I doubt modern compilers can also be relied on 100%.
In large projects where Macro's are extensively used, I have seen rare scenarios where even Kloclwork /Purify have failed to find non-initialized usage.
So I say stick with it as long as you are using plain old C/C++.
Modern languages like .Net can guarantee to initialize varaibles, or give a compiler error for uninitialized variable usage. Following link does a performance analysis and validates that there is a 10-20% performance hit for .NET. The analysis is in quite detail and is explained well.
http://www.codeproject.com/KB/dotnet/DontInitializeVariables.aspx
Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I know there is a standard behind all C compiler implementations, so there should be no hidden features. Despite that, I am sure all C developers have hidden/secret tricks they use all the time.
More of a trick of the GCC compiler, but you can give branch indication hints to the compiler (common in the Linux kernel)
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
see: http://kerneltrap.org/node/4705
What I like about this is that it also adds some expressiveness to some functions.
void foo(int arg)
{
if (unlikely(arg == 0)) {
do_this();
return;
}
do_that();
...
}
int8_t
int16_t
int32_t
uint8_t
uint16_t
uint32_t
These are an optional item in the standard, but it must be a hidden feature, because people are constantly redefining them. One code base I've worked on (and still do, for now) has multiple redefinitions, all with different identifiers. Most of the time it's with preprocessor macros:
#define INT16 short
#define INT32 long
And so on. It makes me want to pull my hair out. Just use the freaking standard integer typedefs!
The comma operator isn't widely used. It can certainly be abused, but it can also be very useful. This use is the most common one:
for (int i=0; i<10; i++, doSomethingElse())
{
/* whatever */
}
But you can use this operator anywhere. Observe:
int j = (printf("Assigning variable j\n"), getValueFromSomewhere());
Each statement is evaluated, but the value of the expression will be that of the last statement evaluated.
initializing structure to zero
struct mystruct a = {0};
this will zero all stucture elements.
Function pointers. You can use a table of function pointers to implement, e.g., fast indirect-threaded code interpreters (FORTH) or byte-code dispatchers, or to simulate OO-like virtual methods.
Then there are hidden gems in the standard library, such as qsort(),bsearch(), strpbrk(), strcspn() [the latter two being useful for implementing a strtok() replacement].
A misfeature of C is that signed arithmetic overflow is undefined behavior (UB). So whenever you see an expression such as x+y, both being signed ints, it might potentially overflow and cause UB.
Multi-character constants:
int x = 'ABCD';
This sets x to 0x41424344 (or 0x44434241, depending on architecture).
EDIT: This technique is not portable, especially if you serialize the int.
However, it can be extremely useful to create self-documenting enums. e.g.
enum state {
stopped = 'STOP',
running = 'RUN!',
waiting = 'WAIT',
};
This makes it much simpler if you're looking at a raw memory dump and need to determine the value of an enum without having to look it up.
I never used bit fields but they sound cool for ultra-low-level stuff.
struct cat {
unsigned int legs:3; // 3 bits for legs (0-4 fit in 3 bits)
unsigned int lives:4; // 4 bits for lives (0-9 fit in 4 bits)
// ...
};
cat make_cat()
{
cat kitty;
kitty.legs = 4;
kitty.lives = 9;
return kitty;
}
This means that sizeof(cat) can be as small as sizeof(char).
Incorporated comments by Aaron and leppie, thanks guys.
C has a standard but not all C compilers are fully compliant (I've not seen any fully compliant C99 compiler yet!).
That said, the tricks I prefer are those that are non-obvious and portable across platforms as they rely on the C semantic. They usually are about macros or bit arithmetic.
For example: swapping two unsigned integer without using a temporary variable:
...
a ^= b ; b ^= a; a ^=b;
...
or "extending C" to represent finite state machines like:
FSM {
STATE(x) {
...
NEXTSTATE(y);
}
STATE(y) {
...
if (x == 0)
NEXTSTATE(y);
else
NEXTSTATE(x);
}
}
that can be achieved with the following macros:
#define FSM
#define STATE(x) s_##x :
#define NEXTSTATE(x) goto s_##x
In general, though, I don't like the tricks that are clever but make the code unnecessarily complicated to read (as the swap example) and I love the ones that make the code clearer and directly conveying the intention (like the FSM example).
Interlacing structures like Duff's Device:
strncpy(to, from, count)
char *to, *from;
int count;
{
int n = (count + 7) / 8;
switch (count % 8) {
case 0: do { *to = *from++;
case 7: *to = *from++;
case 6: *to = *from++;
case 5: *to = *from++;
case 4: *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
}
I'm very fond of designated initializers, added in C99 (and supported in gcc for a long time):
#define FOO 16
#define BAR 3
myStructType_t myStuff[] = {
[FOO] = { foo1, foo2, foo3 },
[BAR] = { bar1, bar2, bar3 },
...
The array initialization is no longer position dependent. If you change the values of FOO or BAR, the array initialization will automatically correspond to their new value.
C99 has some awesome any-order structure initialization.
struct foo{
int x;
int y;
char* name;
};
void main(){
struct foo f = { .y = 23, .name = "awesome", .x = -38 };
}
anonymous structures and arrays is my favourite one. (cf. http://www.run.montefiore.ulg.ac.be/~martin/resources/kung-f00.html)
setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));
or
void myFunction(type* values) {
while(*values) x=*values++;
}
myFunction((type[]){val1,val2,val3,val4,0});
it can even be used to instanciate linked lists...
gcc has a number of extensions to the C language that I enjoy, which can be found here. Some of my favorites are function attributes. One extremely useful example is the format attribute. This can be used if you define a custom function that takes a printf format string. If you enable this function attribute, gcc will do checks on your arguments to ensure that your format string and arguments match up and will generate warnings or errors as appropriate.
int my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
the (hidden) feature that "shocked" me when I first saw is about printf. this feature allows you to use variables for formatting format specifiers themselves. look for the code, you will see better:
#include <stdio.h>
int main() {
int a = 3;
float b = 6.412355;
printf("%.*f\n",a,b);
return 0;
}
the * character achieves this effect.
Well... I think that one of the strong points of C language is its portability and standardness, so whenever I find some "hidden trick" in the implementation I am currently using, I try not to use it because I try to keep my C code as standard and portable as possible.
Compile-time assertions, as already discussed here.
//--- size of static_assertion array is negative if condition is not met
#define STATIC_ASSERT(condition) \
typedef struct { \
char static_assertion[condition ? 1 : -1]; \
} static_assertion_t
//--- ensure structure fits in
STATIC_ASSERT(sizeof(mystruct_t) <= 4096);
Constant string concatenation
I was quite surprised not seeing it allready in the answers, as all compilers I know of support it, but many programmers seems to ignore it. Sometimes it's really handy and not only when writing macros.
Use case I have in my current code:
I have a #define PATH "/some/path/" in a configuration file (really it is setted by the makefile). Now I want to build the full path including filenames to open ressources. It just goes to:
fd = open(PATH "/file", flags);
Instead of the horrible, but very common:
char buffer[256];
snprintf(buffer, 256, "%s/file", PATH);
fd = open(buffer, flags);
Notice that the common horrible solution is:
three times as long
much less easy to read
much slower
less powerfull at it set to an arbitrary buffer size limit (but you would have to use even longer code to avoid that without constant strings contatenation).
use more stack space
Well, I've never used it, and I'm not sure whether I'd ever recommend it to anyone, but I feel this question would be incomplete without a mention of Simon Tatham's co-routine trick.
When initializing arrays or enums, you can put a comma after the last item in the initializer list. e.g:
int x[] = { 1, 2, 3, };
enum foo { bar, baz, boom, };
This was done so that if you're generating code automatically you don't need to worry about eliminating the last comma.
Struct assignment is cool. Many people don't seem to realize that structs are values too, and can be assigned around, there is no need to use memcpy(), when a simple assignment does the trick.
For example, consider some imaginary 2D graphics library, it might define a type to represent an (integer) screen coordinate:
typedef struct {
int x;
int y;
} Point;
Now, you do things that might look "wrong", like write a function that creates a point initialized from function arguments, and returns it, like so:
Point point_new(int x, int y)
{
Point p;
p.x = x;
p.y = y;
return p;
}
This is safe, as long (of course) as the return value is copied by value using struct assignment:
Point origin;
origin = point_new(0, 0);
In this way you can write quite clean and object-oriented-ish code, all in plain standard C.
Strange vector indexing:
int v[100]; int index = 10;
/* v[index] it's the same thing as index[v] */
C compilers implement one of several standards. However, having a standard does not mean that all aspects of the language are defined. Duff's device, for example, is a favorite 'hidden' feature that has become so popular that modern compilers have special purpose recognition code to ensure that optimization techniques do not clobber the desired effect of this often used pattern.
In general hidden features or language tricks are discouraged as you are running on the razor edge of whichever C standard(s) your compiler uses. Many such tricks do not work from one compiler to another, and often these kinds of features will fail from one version of a compiler suite by a given manufacturer to another version.
Various tricks that have broken C code include:
Relying on how the compiler lays out structs in memory.
Assumptions on endianness of integers/floats.
Assumptions on function ABIs.
Assumptions on the direction that stack frames grow.
Assumptions about order of execution within statements.
Assumptions about order of execution of statements in function arguments.
Assumptions on the bit size or precision of short, int, long, float and double types.
Other problems and issues that arise whenever programmers make assumptions about execution models that are all specified in most C standards as 'compiler dependent' behavior.
When using sscanf you can use %n to find out where you should continue to read:
sscanf ( string, "%d%n", &number, &length );
string += length;
Apparently, you can't add another answer, so I'll include a second one here, you can use "&&" and "||" as conditionals:
#include <stdio.h>
#include <stdlib.h>
int main()
{
1 || puts("Hello\n");
0 || puts("Hi\n");
1 && puts("ROFL\n");
0 && puts("LOL\n");
exit( 0 );
}
This code will output:
Hi
ROFL
using INT(3) to set break point at the code is my all time favorite
My favorite "hidden" feature of C, is the usage of %n in printf to write back to the stack. Normally printf pops the parameter values from the stack based on the format string, but %n can write them back.
Check out section 3.4.2 here. Can lead to a lot of nasty vulnerabilities.
Compile-time assumption-checking using enums:
Stupid example, but can be really useful for libraries with compile-time configurable constants.
#define D 1
#define DD 2
enum CompileTimeCheck
{
MAKE_SURE_DD_IS_TWICE_D = 1/(2*(D) == (DD)),
MAKE_SURE_DD_IS_POW2 = 1/((((DD) - 1) & (DD)) == 0)
};
Gcc (c) has some fun features you can enable, such as nested function declarations, and the a?:b form of the ?: operator, which returns a if a is not false.
I discoverd recently 0 bitfields.
struct {
int a:3;
int b:2;
int :0;
int c:4;
int d:3;
};
which will give a layout of
000aaabb 0ccccddd
instead of without the :0;
0000aaab bccccddd
The 0 width field tells that the following bitfields should be set on the next atomic entity (char)
C99-style variable argument macros, aka
#define ERR(name, fmt, ...) fprintf(stderr, "ERROR " #name ": " fmt "\n", \
__VAR_ARGS__)
which would be used like
ERR(errCantOpen, "File %s cannot be opened", filename);
Here I also use the stringize operator and string constant concatentation, other features I really like.
Variable size automatic variables are also useful in some cases. These were added i nC99 and have been supported in gcc for a long time.
void foo(uint32_t extraPadding) {
uint8_t commBuffer[sizeof(myProtocol_t) + extraPadding];
You end up with a buffer on the stack with room for the fixed-size protocol header plus variable size data. You can get the same effect with alloca(), but this syntax is more compact.
You have to make sure extraPadding is a reasonable value before calling this routine, or you end up blowing the stack. You'd have to sanity check the arguments before calling malloc or any other memory allocation technique, so this isn't really unusual.