141

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.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
bernardn
  • 1,701
  • 5
  • 19
  • 23
  • It'd be great if you/someone were to edit the “question” to indicate the pick of the best hidden features, such as in the C# and Perl versions of this question. – Donal Fellows May 26 '10 at 13:19

56 Answers56

115

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();
     ...
}
tonylo
  • 3,311
  • 3
  • 28
  • 27
77
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!

Ben Collins
  • 20,538
  • 18
  • 127
  • 187
  • 3
    I think they are C99 or so. I haven't found a portable way to ensure these would be around. – akauppi Sep 25 '08 at 19:25
  • 3
    They are an optional part of C99, but I know of no compiler vendors that don't implement this. – Ben Collins Sep 25 '08 at 21:07
  • 10
    stdint.h isn't optional in C99, but following the C99 standard apparently is for some vendors (*cough* Microsoft). – Ben Combee Oct 22 '08 at 17:54
  • 1
    Microsoft Visual C++ doesn't follow the Ada95 standard either. It's not a C99 compiler. It's a C++ 97 compiler. (It doesn't always follow that standard, but it's not fair to complain about it not being something it doesn't claim to be) – Pete Kirkham Mar 01 '09 at 11:33
  • 5
    @Pete, if you want to be anal: (1) This thread has nothig to do with any Microsoft product. (2) This thread never had anything to do with C++ at all. (3) There is no such thing as C++ 97. – Ben Collins Mar 01 '09 at 21:20
  • 5
    Have a look at http://www.azillionmonkeys.com/qed/pstdint.h -- a close-to-portable stdint.h – gnud Apr 16 '09 at 14:16
  • 1
    @gnud: thanks for the tip, but my whole gripe is that it isn't necessary - most compilers implement the standard typedefs. The only compiler I've ever used that didn't was an old version of GCC adapted for embedded VxWorks development (old, like, GCC 2.7). – Ben Collins Apr 16 '09 at 21:56
  • @Ben Collins: He's pointing out that it almost implements C++98, but falls short of several requirements. Furthermore, MSVC _doesn't_ support C99, especially stdint.h which is a royal PITA. – Matt Joiner Oct 22 '09 at 11:52
  • 1
    @Anacrolix: Yes. I understood what he was pointing out. You seem to miss my point though: it's apropos nothing. Whether or not a particular compiler "supports C99" really has nothing at all to do with whether or not you should use the standard integer typedefs. They are portable and easy to define even if your compiler sucks. If you need to specify a certain integer width, then the standard typedefs should *always*, **always** be used, regardless of where the definitions come from. – Ben Collins Oct 23 '09 at 21:59
  • 1
    Thanks so much! It gets my back up when I use the Windows headers and you get typedef unsigned long ULONG. Like, seriously? Or, typedef float FLOAT. – Puppy May 08 '10 at 08:58
  • 3
    To my knowledge, Visual Studio 2010 now has stdint.h due to high demand for that specific feature of C99. It was a royal PITA that it wasn't included earlier than that. – Jonathan Sternberg Jan 19 '11 at 21:12
72

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.

Ben Collins
  • 20,538
  • 18
  • 127
  • 187
63

initializing structure to zero

struct mystruct a = {0};

this will zero all stucture elements.

mike511
  • 1,685
  • 4
  • 16
  • 18
  • Does it zero out an entire array, as well? – Nate Parsons Dec 28 '08 at 03:30
  • 2
    It doesn't zero the padding, if any, however. – Mikeage Mar 01 '09 at 13:49
  • @drhorrible: You can do int array[50] = {0}; for example. But only at declaration (I think.) – Skurmedel Apr 26 '09 at 11:08
  • Doesn't this do something undefined if the structure contains non-integral types (e.g. floats and doubles)? – Simon Nickerson Jun 11 '09 at 11:20
  • 2
    @simonn, no it doesn't do undefined behavior if the structure contains non-integral types. memset with 0 on the memory of a float/double will still be zero when you interpret the float/double (float/double are designed like that on purpose). – Trevor Boyd Smith Jun 11 '09 at 13:59
  • @Trevor I thought that the effect this has on floats and such is "all bytes zero" which, in all sane cases, would give you a float equal to 0.0, but it's still implementation-defined. – Andrew Keeton Jun 22 '09 at 00:27
  • 6
    @Andrew: `memset`/`calloc` do "all bytes zero" (i.e. physical zeroes), which is indeed not defined for all types. `{ 0 } ` is guaranteed to intilaize *everything* with proper *logical* zero values. Pointers, for example, are guranteed to get their proper null values, even if the null-value on the given platform is `0xBAADFOOD`. – AnT stands with Russia Oct 28 '09 at 10:12
  • @AndreyT: Could you please elaborate on diff between logical and physical zeroes? – N 1.1 Feb 26 '10 at 09:38
  • 1
    @nvl: You get *physical* zero when you just forcefully set all memory occupied by the object to all-bits-zero state. This is what `memset` does (with `0` as second argument). You get *logical* zero when you initialize/assign `0` ( or `{ 0 }`) to the object in the source code. These two kinds of zeros do not necessarily produce the same result. As in the example with pointer. When you do `memset` on a pointer, you get a `0x0000` pointer. But when you assign `0` to a pointer, you get *null pointer value*, which at the physical level might be `0xBAADF00D` or anything else. – AnT stands with Russia Feb 26 '10 at 16:29
  • In other words, *physical* value is the explicit bit-pattern that is stored in memory. *Logical* value is how that bit-pattern is interpreted at the program level. – AnT stands with Russia Feb 26 '10 at 16:31
  • @AndreyT I am clear about the physical zero thing. But cannot digest this logical zeroes completely. Any other data structure, other than pointer, which has different logical/physical representations? – N 1.1 Feb 26 '10 at 18:57
  • 3
    @nvl: Well, in practice the difference is often only conceptual. But in theory, virtually any type can have it. For example, `double`. Usually it is implemented in accordance with IEEE-754 standard, in which the logical zero and physical zero are the same. But IEEE-754 is not required by the language. So it might happen that when you do `double d = 0;` (logical zero), physically some bits in memory occupied by `d` will not be zero. – AnT stands with Russia Feb 26 '10 at 19:17
  • 1
    Same with `bool` values, for another example. If you do `bool b = false;` (or, equivalently, `bool b = 0;`) it does not necessarily mean that in physical memory `b` will be zeroed out (even though it is usually the case in practice). – AnT stands with Russia Feb 26 '10 at 19:18
  • 1
    Got it. Thanks. I remember the floating point representation now. Makes sense. – N 1.1 Feb 26 '10 at 21:10
62

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.

zvrba
  • 24,186
  • 3
  • 55
  • 65
  • 29
    But if they had specified behaviour on overflow, it would have made it very slow on architectures where that was not the normal behaviour. Very low runtime overhead has always been a design goal of C, and that has meant that a lot of things like this are undefined. – Mark Baker Oct 17 '08 at 08:38
  • 9
    I'm very well aware of _why_ overflow is UB. It is still a misfeature, because the standard should have at least provided library routines that can test for arithmetic overflow (of all basic operations) w/o causing UB. – zvrba Jan 20 '09 at 20:51
  • 2
    @zvrba, "library routines that can test for arithmetic overflow (of all basic operations)" if you had added this then you would have incurred significant performance hit for any integer arithmetic operations. ===== Case study Matlab specifically ADDS the feature of controlling integer overflow behavior to wrapping or saturate. And it also throws an exception whenever overflow occurs ==> Performance of Matlab integer operations: VERY SLOW. My own conclusion: I think Matlab is a compelling case study that shows why you don't want integer overflow checking. – Trevor Boyd Smith Jun 11 '09 at 13:35
  • 1
    @zvrba, In my opinion, C was designed ASSUMING that whenever you are doing integer arithmetic you the programmer are doing rigorous analysis to ENSURE that you have bounded-input-bounded-output (fancy way of saying "make sure your input and output stay within a range")!! If you are not doing that rigorous analysis then it's not the language's fault it is the programmer's fault. – Trevor Boyd Smith Jun 11 '09 at 13:38
  • 15
    I said that the standard should have provided *library* support for checking for arithmetic overflow. Now, how can a library routine incur a performance hit if you never use it? – zvrba Jun 12 '09 at 18:52
  • 5
    A big negative is that GCC does not have a flag to catch signed integer overflows and throw a runtime exception. While there are x86 flags for detecting such cases, GCC does not utilize them. Having such a flag would allow non-performance-critical (especially legacy) applications the benefit of security with minimal to no code review and refactoring. – Andrew Keeton Jun 22 '09 at 00:23
  • None of this is at all 'hidden'. The standard library for example is well advertised; if people choose not to read the documentation they are fools. Function pointers are merely 'advanced' not hidden in any way whatsoever - most texts on the language deal with them. – Clifford Nov 11 '09 at 13:52
  • Hidden is relative, documentation is relatively absolute. – Anonymous Type Sep 02 '10 at 01:08
  • what is the need of an strtok replacement? – Aif Nov 26 '10 at 13:57
52

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.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • I'm pretty sure this is not a portable construct. The result of creating a multi-character constant is implementation-defined. – Mark Bessey Oct 17 '08 at 04:18
  • remove the comma after 'WAIT' in case someone tries this. – blak3r Jun 11 '09 at 07:11
  • @blak3r - thanks! that reminds me of another hidden feature. see here: http://stackoverflow.com/questions/132241/hidden-features-of-c/980530#980530 – Ferruccio Jun 11 '09 at 11:17
  • A problem is that it cannot be compared with real strings, since depending on endianness it can be stored in memory as "STOP" or "POTS". – calandoa Jun 22 '09 at 11:51
  • It is not intended to be compared to real strings. The point is that you can give enums unique values that are easy to read in a memory dump. – Ferruccio Jun 22 '09 at 12:20
  • The comma was intentional and syntactically valid. – Ferruccio Jun 22 '09 at 19:11
  • @Ferruccio - I believe the comma is valid in C99, but not C89. Which means GCC will probably swallow it, but some older compilers (or older GCC versions) won't. – Chris Lutz Aug 23 '09 at 22:24
  • 8
    The "not portable" comments miss the point entirely. It is like criticizing a program for using INT_MAX just because INT_MAX is "not portable" :) This feature is as portable as it needs to be. Multi-char constant is an extremely useful feature that provides readable way to for generating unique integer IDs. – AnT stands with Russia Oct 28 '09 at 10:36
  • 1
    @Chris Lutz - I'm pretty sure the trailing comma goes all the way back to K&R. It's described in the second edition (1988). – Ferruccio Oct 28 '09 at 11:15
  • 1
    @Ferruccio: You must be thinking about the trailing comma in the aggregate initailizer lists. As for the trailing comma in enum declarations - it's a recent addition, C99. – AnT stands with Russia Oct 28 '09 at 17:59
  • 3
    You forgot 'HANG' or 'BSOD' :-) – JBRWilkinson Nov 02 '09 at 16:30
  • Why not just use macros with defined numerical flags? – Vince Feb 11 '10 at 00:58
  • @Vince: Macros, even for constant, pollute the namespace of the program. On similar lines, Why not use assembly instead of C? ;) – Joe D Jun 07 '10 at 18:23
  • I tested and at least with gcc (tried on PowerPC and x86) multi-bytes characters do not depend on endianness. Did someone tried with another compiler or checked ISO standard ? The answer above seems wrong about endianness. – kriss Mar 29 '11 at 09:51
44

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.

Community
  • 1
  • 1
Motti
  • 110,860
  • 49
  • 189
  • 262
  • The combination of structs and unions is even more interesting - on embedded systems or low level driver code. An example is when you like to parse the registers of an SD card, you can read it in using union (1) and read it out using union (2) which is a struct of bitfields. – ComSubVie Sep 25 '08 at 11:09
  • 5
    Bitfields are not portable -- the compiler can choose freely whether, in your example, legs will be allocated the most significant 3 bits, or the least significant 3 bits. – zvrba Sep 25 '08 at 14:25
  • 3
    Bitfields are an example of where the standard gives implementations so much freedom in how they're inplemented, that in practice, they're nearly useless. If you care how many bits a value takes up, and how it's stored, you're better off using bitmasks. – Mark Bessey Oct 17 '08 at 04:13
  • 26
    Bitfields are indeed portable as long as you treat them as the structure elements they are, and not "pieces of integers." Size, not location, matters in an embedded system with limited memory, as each bit is precious ... but most of today's coders are too young to remember that. :-) – Adam Liss Oct 26 '08 at 00:41
  • Yay for bitfields! I use them all the time. – c0m4 Nov 13 '08 at 21:40
  • 5
    @Adam: location may well matter in an embedded system (or elsewhere), if you are depending on the position of the bitfield within its byte. Using masks removes any ambiguity. Similarly for unions. – Steve Melnikoff Mar 01 '09 at 22:51
  • @ComSubVie: from this point of view, nothing is ever portable :) – AnT stands with Russia Oct 28 '09 at 10:14
  • Yes, I actually used this for an assignment I had in my CS class last year. We implemented the LZW algorithm to run under a specific memory constraint. The only option was to specify number of bits to use for each field in the struct because the default made each field too large. – dougvk Oct 14 '10 at 07:45
37

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);
    }
}
SiegeX
  • 135,741
  • 24
  • 144
  • 154
ComSubVie
  • 1,609
  • 1
  • 16
  • 20
  • I don't understand this. I've added the link, it is displayed in the preview, but not in the final post... – ComSubVie Sep 25 '08 at 14:00
  • This is not a proper strcpy function - this implementation assumes that "to" is a memory-mapped register. – Adam Rosenfield Sep 25 '08 at 14:23
  • @ComSubVie: you created the link, but have't instantiated it. You need to add something like this to the answer: "[Wikipedia article][1] on Duff's device." Personally I dislike the Markdown notation for links, I tend to use HTML anchor tags directly. – DGentry Sep 25 '08 at 16:36
  • 29
    @ComSubVie, anyone who uses Duff's Device is a script kiddy who saw Duff's Device and thought their code would look 1337 if they used Duff's Device. (1.) Duff's Device doesn't offer any performance increases on modern processor because modern processors have zero-overhead-looping. In other words it is an obsolete piece of code. (2.) Even if your processor doesn't offer zero-overhead-looping, it will probably have something like SSE/altivec/vector-processing which will put your Duff's Device to shame when you use memcpy(). (3.) Did I mention that other that doing memcpy() duff's is not useful? – Trevor Boyd Smith Jun 11 '09 at 13:50
  • 2
    @ComSubVie, please meet my Fist-of-death (http://en.wikipedia.org/wiki/Alice_(Dilbert_character)#Alice.27s_violent_nature) – Trevor Boyd Smith Jun 11 '09 at 13:52
  • That's ... that's HORRIBLE. why would anyone want to do that to poor defenseless code? – Brian Postow Nov 03 '09 at 15:11
  • 12
    @Trevor: so only script kiddies program 8051 and PIC microcontrollers, right? – SF. Feb 19 '10 at 11:13
  • 6
    @Trevor Boyd Smith : While the Duff's Device appears outdated, it's still an historical curiosity, which validates ComSubVie's answer. Anyway, quoting Wikipedia : *"When numerous instances of Duff's device were removed from the XFree86 Server in version 4.0, there was a notable improvement in performance."*... – paercebal May 08 '10 at 09:01
  • 2
    On Symbian, we once evaluated various loops for fast pixel coding; the duff's device, in assembler, was the fastest. So it still had relevance on the mainstream ARM cores on your smartphones today. – Will Oct 25 '10 at 08:37
  • @Trevor: While Duff's device may be outdated (it isn't), the concept behind it (loop unrolling) is not. – Michael Foukarakis Aug 11 '11 at 05:45
37

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).

Remo.D
  • 16,122
  • 6
  • 43
  • 74
  • 18
    C supports chaining, so you can do a ^= b ^= a ^= b; – OJ. Sep 25 '08 at 10:06
  • 4
    Strictly speaking, the state example is a tick of the preprocessor, and not the C language - it is possible to use the former without the latter. – Greg Whitfield Sep 25 '08 at 13:10
  • 15
    OJ: actually what you suggest is undefined behavior because of sequence point rules. It may work on most compilers, but is not correct or portable. – Evan Teran Sep 25 '08 at 14:14
  • 2
    Using an XOR swap is generally a bad idea, mostly because it works only for integers and aliasing can prove to be a big problem. I'm pretty sure that most compilers optimize it when memory becomes an issue. – user9282 Sep 25 '08 at 14:24
  • 5
    Xor swap could actually be less efficient in the case of a free register. Any decent optimizer would make the temp variable be a register. Depending on implementation (and need for parallelism support) the swap might actually use real memory instead of a register (which would be the same). – Paul de Vrieze Oct 17 '08 at 09:49
  • 27
    please don't ever actually do this: http://en.wikipedia.org/wiki/Xor_swap#Reasons_for_avoidance_in_practice – Christian Oudard Jan 02 '09 at 18:55
  • 1
    Why would you do this? other than to raise a host of serious static analysis warnings. Use a switch case statement wrapped in a while loop. – Oliver Jul 09 '09 at 16:23
  • 2
    @OJ: No, this is undefined behavior. – AnT stands with Russia Oct 28 '09 at 10:13
  • 2
    XOR swapping fails if 'a' is alias to 'b' – Adrian Panasiuk Nov 05 '09 at 19:43
  • 2
    OJ: I used to do it with GCC... until I tried to compile a small example to MIPS and a lost a lot of time debugging because it was compiling somehow different. As they told here: it is undefined. – dbarbosa Sep 17 '10 at 04:04
33

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.

DGentry
  • 16,111
  • 8
  • 50
  • 66
28

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 };
}

Vicky Chijwani
  • 10,191
  • 6
  • 56
  • 79
27

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...

PypeBros
  • 2,607
  • 24
  • 37
  • 3
    This feature is usually called "compound literals". Anonymous (or unnamed) structures designate nested structures that have no member names. – calandoa Jun 22 '09 at 11:47
  • according to my GCC, "ISO C90 forbids compound literals". – jmtd Jun 22 '09 at 15:55
  • "ISO C99 supports compound literals." "As an extension, GCC supports compound literals in C89 mode and in C++" (dixit info gcc). Plus, "As a GNU extension, GCC allows initialization of objects with static storage duration by compound literals (which is not possible in ISO C99, because the initializer is not a constant)." – PypeBros Feb 03 '11 at 17:31
24

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.

kolistivra
  • 4,229
  • 9
  • 45
  • 58
24

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.

philant
  • 34,748
  • 11
  • 69
  • 112
Giacomo Degli Esposti
  • 2,392
  • 1
  • 15
  • 20
  • But in reality, how often do you have to compile your code with another compiler? – Joe D Jun 07 '10 at 18:26
  • 3
    @Joe D if its a cross platform project like Windows/OSX/Linux, probably a bit, and also there's different arch such as x86 vs x86_64 and etc... – Pharaun Nov 11 '10 at 17:13
  • @JoeD Unless you're in a very narrowminded project that's happy to marry one compiler vendor, very. You might want to avoid actually having to switch compilers, but you do want to keep that option open. With embedded systems, you don't always get a choice, though. AHS, ASS. – XTL Feb 17 '12 at 07:34
24

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)));
Russell Bryant
  • 1,731
  • 1
  • 10
  • 8
19

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);
Community
  • 1
  • 1
philant
  • 34,748
  • 11
  • 69
  • 112
16

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
kriss
  • 23,497
  • 17
  • 97
  • 116
  • 1
    It is also useful to split a string constant on multiple source lines without using dirty `\\`. – dolmen Mar 28 '11 at 21:35
15

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.

Mark Baker
  • 5,588
  • 2
  • 27
  • 25
12

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.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • 4
    Of course, there are performance implications to passing round large structs in this way; it's often useful (and is indeed something a lot of people don't realise you can do) but you need to consider whether passing pointers is better. – Mark Baker Oct 17 '08 at 08:47
  • 1
    Of course, there *might* be. Ít's also quite possible for the compiler to detect the usage and optimize it. – unwind Oct 17 '08 at 08:57
  • Be careful if any of the elements are pointers, as you'll be copying the pointers themselves, not their contents. Of course, the same is true if you use memcpy(). – Adam Liss Oct 26 '08 at 00:27
  • The compiler can't optimize this converting by-value passing with by-referenece, unless it can do global optimizations. – Blaisorblade Jan 19 '09 at 00:20
  • It's probably worth noting that in C++ the standard specifically allows optimizing away the copy (the standard has to allow for it for compilers to implement it because it means the copy constructor which may have side effects may not be called), and since most C++ compilers are also C compilers, there's a good chance your compiler does do this optimization. – Joseph Garvin Feb 21 '10 at 17:05
  • I fixed the final "constructor" call, it was calling Point(0, 0) which of course is wrong, point_new() is the way to go. Oops. – unwind Oct 25 '10 at 08:33
  • C99 structure initialization is designed to be optimized while this code relies on the fact that the compiler MAY inline the function AND MAY drop the copy. – dolmen Mar 28 '11 at 21:26
12

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.

Ferruccio
  • 98,941
  • 38
  • 226
  • 299
  • This is also important in a multi-developer environment where, for instance, Eric adds in "baz," and then George adds in "boom,". If Eric decides to pull his code out for the next project build, it still compiles with George's change. Very important for multi-branch source code control and overlapping development schedules. – Harold Bamford Jun 30 '09 at 21:50
  • Enums may be C99. Array initializers & the trailing comma are K&R. – Ferruccio Nov 24 '09 at 11:27
  • Plain enums were in c89, AFAIK. At least they've been around for ages. – XTL Feb 17 '12 at 07:48
10

Strange vector indexing:

int v[100]; int index = 10; 
/* v[index] it's the same thing as index[v] */
INS
  • 10,594
  • 7
  • 58
  • 89
9

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:

  1. Relying on how the compiler lays out structs in memory.
  2. Assumptions on endianness of integers/floats.
  3. Assumptions on function ABIs.
  4. Assumptions on the direction that stack frames grow.
  5. Assumptions about order of execution within statements.
  6. Assumptions about order of execution of statements in function arguments.
  7. 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.

Kevin S.
  • 863
  • 6
  • 9
  • To solve most of those, make those assumptions dependant on the characteristics of your platform, and describe each platform in his own header. Order execution is an exception - never rely on that; on the other ideas, each platform needs having a reliable decision. – Blaisorblade Jan 19 '09 at 00:17
  • 2
    @Blaisorblade, Even better, use compile-time assertions to document your assumptions in a way that will make the compile fail on a platform where they are violated. – RBerteig Aug 01 '10 at 00:06
  • I think one should combine both, so that your code works on multiple platforms (that was the original intention), and if the feature macros are set the wrong way, compile-time assertions will catch it. I'm not sure if, say, assumption on function ABIs are checkable as compile-time assertions, but it should be possible for most of the other (valid) ones (except order of execution ;-)). – Blaisorblade Aug 02 '10 at 13:01
  • Function ABI checks should be handled by a test suite. – dolmen Mar 28 '11 at 21:30
9

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
ulidtko
  • 14,740
  • 10
  • 56
  • 88
onemasse
  • 6,514
  • 8
  • 32
  • 37
8

using INT(3) to set break point at the code is my all time favorite

Dror Helper
  • 30,292
  • 15
  • 80
  • 129
8

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.

Sridhar Iyer
  • 2,772
  • 1
  • 21
  • 28
  • the link is not working anymore, in fact the site itself seems is not working. Can you provide another link? – thequark Jan 07 '11 at 04:39
  • @thequark: Any article on "format string vulnerabilities" will have some info in it.. (e.g. http://crypto.stanford.edu/cs155/papers/formatstring-1.2.pdf) .. However due to the nature of the field, the security websites themselves are a bit flaky and real academic articles are hard to come by (with implementation). – Sridhar Iyer Jan 07 '11 at 07:08
8

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)
};
S.C. Madsen
  • 5,100
  • 5
  • 32
  • 50
  • 2
    +1 Neat. I used to use the CompilerAssert macro from Microsoft, but yours is not bad either. (`#define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1]`) – Patrick Schlüter Nov 27 '10 at 12:52
  • 1
    I like the enumeration method. The approach I'd used before took advantage of dead code elimination: "if (something_bad) {void BLORG_IS_WOOZLED(void); BLORG_IS_WOOZLED();}" which didn't error until link time, though it did offer the advantage of letting the programmer know via error message that the blorg was woozled. – supercat Aug 25 '11 at 21:28
8

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)

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
8

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.

ulidtko
  • 14,740
  • 10
  • 56
  • 88
Alex Brown
  • 41,819
  • 10
  • 94
  • 108
7

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.

Ben Combee
  • 16,831
  • 6
  • 41
  • 42
6

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.

DGentry
  • 16,111
  • 8
  • 50
  • 66
  • Will this also work correctly if a byte/char is not exactly 8 bits wide on the target platform? I know, those cases are rare, but still... :) – Stephan202 Apr 26 '09 at 10:26
5

I liked the variable sized structures you could make:

typedef struct {
    unsigned int size;
    char buffer[1];
} tSizedBuffer;

tSizedBuffer *buff = (tSizedBuffer*)(malloc(sizeof(tSizedBuffer) + 99));

// can now refer to buff->buffer[0..99].

Also the offsetof macro which is now in ANSI C but was a piece of wizardry the first time I saw it. It basically uses the address-of operator (&) for a null pointer recast as a structure variable.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    This is not standard compliant; C99 has 'flexible array members' which achieve the same result and are compliant. (Drop the `1` from the declaration to use a flexible array member.) – Jonathan Leffler Jan 18 '12 at 01:53
5

Lambda's (e.g. anonymous functions) in GCC:

#define lambda(return_type, function_body) \
    ({ return_type fn function_body fn })

This can be used as:

lambda (int, (int x, int y) { return x > y; })(1, 2)

Which is expanded into:

({ int fn (int x, int y) { return x > y } fn; })(1, 2)
Joe D
  • 2,855
  • 2
  • 31
  • 25
5

I like __LINE__ and __FILE__. See here: http://gcc.gnu.org/onlinedocs/cpp/Standard-Predefined-Macros.html

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Steve Webb
  • 1
  • 1
  • 1
4

For clearing the input buffer you can't use fflush(stdin). The correct way is as follows: scanf("%*[^\n]%*c") This will discard everything from the input buffer.

  • @Tomas Senart. Do you have a reference of that? I totally agree that you can't use fflush(stdin) in order to clean the buffer, that only works on windows c [compiler](http://msdn.microsoft.com/en-us/library/9yky46tz%28v=VS.100%29.aspx) but does not work in gcc. – Cacho Santa Jan 27 '12 at 20:15
3

Early versions of gcc attempted to run a game whenever it encountered "#pragma" in the source code. See also here.

Sec
  • 7,059
  • 6
  • 31
  • 58
  • #pragma GCC poison identifiers This directive bans usage of the identifiers within the program. Poisoned identifiers cannot be #ifdef'd or #undef'd, and attempting to use them for anything will produce an error. Identifiers is a list, separated by spaces. – squadette Jul 12 '10 at 10:14
3

I got shown this in a bit of code once, and asked what it did:


hexDigit = "0123456789abcdef"[someNybble];

Another favorite is:


unsigned char bar[100];
unsigned char *foo = bar;
unsigned char blah = 42[foo];
Andrew Edgecombe
  • 39,594
  • 3
  • 35
  • 61
3

Conversion of types by using unusual typecasts. Though not hidden feature, its quite tricky.

Example:

If you needed to know how compiler stores float, just try this:

uint32_t Int;
float flt = 10.5; // say

Int = *(uint32_t *)&flt;

printf ("Float 10.5 is stored internally as %8X\n", Int);

or

float flt = 10.5; // say

printf ("Float 10.5 is stored internally as %8X\n", *(uint32_t *)&flt);

Note the clever use of typecasts. Converting address of variable (here &flt) to desired type (here (uint32_t * )) and extracting its content (applying '*').

This works other side of expression as well:

*(float *)&Int = flt;

This could also be accomplished using union:

typedef union
{
  uint32_t Int;
  float    flt;

} FloatInt_type;
Chris Lutz
  • 73,191
  • 16
  • 130
  • 183
yogeesh
  • 1,241
  • 8
  • 6
  • 3
    This falls under "common usage that I would recommend against". Type aliasing and optimizations don't get along. Use unions instead for clarity, both for the reader and the compiler. – ephemient Oct 05 '08 at 00:16
  • To be exact, "don't get along" means "this code might be actually miscompiled", because it's undefined behaviour in C. – Blaisorblade Jan 19 '09 at 00:23
3

I only discovered this after 15+ years of C programming:

struct SomeStruct
{
   unsigned a : 5;
   unsigned b : 1;
   unsigned c : 7;
};

Bitfields! The number after the colon is the number of bits the member requires, with members packed into the specified type, so the above would look like the following if unsigned is 16 bits:

xxxc cccc ccba aaaa

Skizz

Skizz
  • 69,698
  • 10
  • 71
  • 108
2

Not really a hidden feature, but it looked to me like voodoo, the first time I saw something like this:


void callback(const char *msg, void *data)
{
    // do something with msg, e.g.
    printf("%s\n", msg);

    return;
    data = NULL;
}

The reason for this construction is, that if you compile this with -Wextra and without the "data = NULL;"-line, gcc will spit out a warning about unused parameters. But with this useless line you don't get a warning.

EDIT: I know there are other (better) ways to prevent those warnings. It just looked strange to me, the first time I saw this.

quinmars
  • 11,175
  • 8
  • 32
  • 41
  • Don't you get a warning about unreachable code instead? Why not just comment out 'data' - that also removes the unused param warning. – Greg Whitfield Sep 25 '08 at 13:15
  • Nope, I didn't get that last time I checked that, but I actually don't use that trick I prefer to use the unused attribute. Removing the data isn't always possible, when you are sticked to the signature because you are writing a callbacks for example. – quinmars Sep 25 '08 at 13:31
  • 1
    No, the signature does not change. You just do this: void callback(const char *msg, void * /* data*/ ) Or this: void callback(const char *msg, void *) – Greg Whitfield Sep 25 '08 at 14:02
  • 1
    With gcc you could add an unused attribute to parameters: void callback(const char *msg, void *data __attribute__((unused))) – DGentry Sep 25 '08 at 14:08
  • 4
    As apposed to using the non-portable __attribute__ syntax. You can just put: (void)data; in the function. I usually put it directly after any locals (as they must be first in c89). I also tend to just make a macro like this: #define UNUSED(x) (void)x so I can just write: UNUSED(data). – Evan Teran Sep 25 '08 at 14:20
  • 1
    You can use '(void)data' anywhere until 'return'. (seems Evan already said that) – akauppi Sep 25 '08 at 19:24
  • @Greg Whitfield void callback(const char *msg, void *) {...} doesn't compile here @all I know that there are many ways how you can suppress this kind of warnings – quinmars Sep 25 '08 at 21:27
  • @quinmars - What compiler are you using? What I told you is simply standard C. What error do you get? – Greg Whitfield Sep 26 '08 at 09:06
  • I'm using gcc, I retried it now with g++ and there indeed it works. So it seems to be a C++ feature. – quinmars Sep 26 '08 at 10:35
  • Can't you also just use #unused data ? – Brian Postow Nov 03 '09 at 15:30
2

intptr_t for declaring variables of type pointer. C99 specific and declared in stdint.h

2

Steve Webb has pointed out the __LINE__ and __FILE__ macros. It reminds me of how in my previous job I had hacked them to have in-memory logging.

I was working on a device where there was no port available to pass logging information from device to the PC being used for debugging. One could use breakpoints to halt and know the state of the program using debugger but there was no information on system trace.

Since all calls to debug logs were effectively a single global macro, we changed that macro to dump file name and line number on to a global array. This array contained series of file names and line numbers showing which debug calls were invoked, giving a fair idea of execution trace (not the actual log message though). One could pause the execution by debugger, dump these bytes onto a local file and then map this information to the code base using scripts. This was made possible because we had strict coding guidelines, so we could make had to make changes to the logging mechanism in one file.

Community
  • 1
  • 1
thequark
  • 726
  • 1
  • 7
  • 17
2

When comparing a variable to a literal, it is better to put the literal to the left of the == operator, to make the sure the compiler gives an error when you mistakenly use the assignment operator instead.

if (0 == count) {
    ...
}

Might look weird at first glance, but it could save some headache (like if you happened to type if (count = 0) by mistake).

Vicky Chijwani
  • 10,191
  • 6
  • 56
  • 79
  • This is an old trick used religiously by some people, but I believe many compilers generate a warning when they see `if (count = 0)` making it somewhat redundant. – Mark Ransom Jan 19 '12 at 17:44
1

Say you have a struct with members of the same type:

struct Point {
    float x;
    float y;
    float z;
};

You can cast instances of it to a float pointer and use array indices:

Point a;
int sum = 0, i = 0;
for( ; i < 3; i++)
    sum += ((float*)a)[i];

Pretty elementary, but useful when writing concise code.

aeflash
  • 39
  • 5
  • 11
    Are you sure this is portable? I thought that the C standards made no guarantee about structure alignment besides the first element being at offset 0. There might be gaps between the elements. I.e. sizeof(Point) is not guaranteed to be sizeof(float)*3. – jmtd Jun 22 '09 at 15:43
  • 1
    @jmtd, Right. In practice its exactly "portable" enough to get you in trouble. The offset of any member other than the first is implementation defined behavior, and need not have the same effective packing as an array of that type. In practice, it is likely it does have the same packing as an array, so this code will work until it is ported to the *next* platform where it will fail mysteriously. A similar thing happened to a common implementation of MD5 when ported to 64-bit: it compiled and ran, but got a different answer. – RBerteig Aug 01 '10 at 00:11
1

Here's three nice ones in gcc:

__FILE__ 
__FUNCTION__
__LINE__
1

register variables

I used to declare some variables with the register keyword to help speed things up. This would give a hint to the C compiler to use a CPU register as local storage. This is most likely no longer necessary as modern day C compilers do this automatically.

Mark Stock
  • 1,713
  • 2
  • 13
  • 23
  • 3
    More to the point the C compiler knows better than you which variables would benefit most from being in a register. Most modern compilers are smart enough to entirely ignore the register keyword, but if they actually paid attention to it it would probably make your code slower – Mark Baker Oct 17 '08 at 08:45
  • 2
    I am pretty sure some compilers refuse to let you take the address of a variable declared with register. So that is useful, in order to keep your intentions clear. – Zan Lynx Jun 11 '09 at 23:00
  • Actually, when you put this to the test, in very specific scenario's with code optimization and perhaps mixed assembly, this keyword does have it merits and can increase speed tremendously. Of course, these are corner cases (one post of me on EE shows just how and when this is useful, but that's a long time ago). – Abel Nov 01 '11 at 17:20
  • Given a combination of a microcontroller and reading the assembly output, this might still be useful in some odd case. – XTL Feb 17 '12 at 07:45
1

Excerpt:

In this page, you will find a list of interesting C programming questions/puzzles, These programs listed are the ones which I have received as e-mail forwards from my friends, a few I read in some books, a few from the internet, and a few from my coding experiences in C.

http://www.gowrikumar.com/c/index.html

Özgür
  • 8,077
  • 2
  • 68
  • 66
1

The size of function pointers is not standard. At least not in the K&R book. Even though it talks about size of other types of pointers but (I think) sizeof of a function pointer is undefined behavior.

Also sizeof is a compile time operator, I see a lot of people asking if sizeof is a function or an operator in online forums.

One error that I have seen is as follows (a simplified example):

int j;
int i;
j = sizeof(i++)

the increment on i would not be executed as sizeof is evaluated at compile time. The programmer intended to hack both operations, increment on i and calculation of sizeof in one statement.

Operator precedence in C governs order of association not order of evaluation. For example if you have three functions f,g,h each returning an int, and their is an expression like:

f() + g() * h()

C standard doesn't give rule about order of evaluation of these functions. Result of g and h would be multiplied before adding result of f. This can lead to error if the functions share state and computation depends on order of evaluation of these functions. This can lead to portability issues.

thequark
  • 726
  • 1
  • 7
  • 17
0

Variable-sized structs, seen in common resolver libs among other places.

struct foo
{
  int a;
  int b;
  char b[1]; // using [0] is no longer correct
             // must come at end
};

char *str = "abcdef";
int len = strlen(str);
struct foo *bar = malloc(sizeof(foo) + len);

strcpy(bar.b, str); // try and stop me!
  • In C99 the correct way to declare that is: `char b[];` which has the advantage that you do not need to subtract the `1*sizeof b[0]` of the size of your struct. – Patrick Schlüter Nov 27 '10 at 12:48
  • 1
    Isn't accessing b[] beyond its declared size undefined behavior, regardless of whether allocated space exists for it? I would think it would be cleaner to use char b[MAX_ARRAY_SIZE] and then subtract MAX_ARRAY_SIZE from the allocation. Better still would have been if zero-size arrays were permitted in the first place, and compilers required to regard them as being a pointer to where the array would start, but without a size limit. – supercat Aug 25 '11 at 21:31
0

Wrap malloc and realloc like this:

#ifdef _DEBUG
#define mmalloc(bytes)                  malloc(bytes);printf("malloc: %d\t<%s@%d>\n", bytes, __FILE__, __LINE__);
#define mrealloc(pointer, bytes)        realloc(pointer, bytes);printf("realloc: %d\t<%s@%d>\n", bytes, __FILE__, __LINE__);
#else //_DEBUG
#define mmalloc(bytes)                  malloc(bytes)
#define mrealloc(pointer, bytes)        realloc(pointer, bytes)

In fact, here is my full arsenol (The BailIfNot is for OO c):

#ifdef _DEBUG
#define mmalloc(bytes)                  malloc(bytes);printf("malloc: %d\t<%s@%d>\n", bytes, __FILE__, __LINE__);
#define mrealloc(pointer, bytes)        realloc(pointer, bytes);printf("realloc: %d\t<%s@%d>\n", bytes, __FILE__, __LINE__);
#define BAILIFNOT(Node, Check)  if(Node->type != Check) return 0;
#define NULLCHECK(var)          if(var == NULL) setError(__FILE__, __LINE__, "Null exception", " var ", FATAL);
#define ASSERT(n)               if( ! ( n ) ) { printf("<ASSERT FAILURE@%s:%d>", __FILE__, __LINE__); fflush(0); __asm("int $0x3"); }
#define TRACE(n)                printf("trace: %s <%s@%d>\n", n, __FILE__, __LINE__);fflush(0);
#else //_DEBUG
#define mmalloc(bytes)                  malloc(bytes)
#define mrealloc(pointer, bytes)        realloc(pointer, bytes)
#define BAILIFNOT(Node, Check)  {}
#define NULLCHECK(var)          {}
#define ASSERT(n)               {}
#define TRACE(n)                {}
#endif //_DEBUG

Here is some example output:

malloc: 12      <hash.c@298>
trace: nodeCreate <hash.c@302>
malloc: 5       <hash.c@308>
malloc: 16      <hash.c@316>
malloc: 256     <hash.c@320>
trace: dataLoadHead <hash.c@441>
malloc: 270     <hash.c@463>
malloc: 262144  <hash.c@467>
trace: dataLoadRecursive <hash.c@404>
  • 4
    please, don't like that... for example, this otherwise correct code `if (something) mmaloc(); else otherthing;` won't compile if _DEBUG is defined. – fortran Oct 28 '09 at 11:24
  • 1
    you want a comma on the malloc macros, not a semicolon (for the reasons @fortran described). That does ignore the return value, though (but then again I'm not sure why these macros are desirable). – Michael Jan 05 '10 at 22:49
0

I just read this article. It has some C and several other languages "hidden features".

Rigo Vides
  • 1,364
  • 13
  • 17
  • Oh my! they're all stackoverflow contributions, sorry (I'm kinda new here and I didn't notice that there's a hidden features section)... Anyway, it may work as a reference and quick guide to these topics. – Rigo Vides Jun 22 '09 at 06:34
0

Object oriented C macros: You need a constructor (init), a destructor (dispose), an equal (equal), a copier (copy), and some prototype for instantiation (prototype).

With the declaration, you need to declare a constant prototype to copy and derive from. Then you can do C_OO_NEW. I can post more examples if needed. LibPurple is a large object oriented C code base with a callback system (if you want to see one in use)

#define C_copy(to, from) to->copy(to, from)

#define true 1
#define false 0
#define C_OO_PROTOTYPE(type)\
void type##_init (struct type##_struct *my);\
void type##_dispose (struct type##_struct *my);\
char type##_equal (struct type##_struct *my, struct type##_struct *yours); \
struct type##_struct * type##_copy (struct type##_struct *my, struct type##_struct *from); \
const type type##__prototype = {type##_init, type##_dispose, type##_equal, type##_copy

#define C_OO_OVERHEAD(type)\
        void (*init) (struct type##_struct *my);\
        void (*dispose) (struct type##_struct *my);\
        char (*equal) (struct type##_struct *my, struct type##_struct *yours); \
        struct type##_struct *(*copy) (struct type##_struct *my, struct type##_struct *from); 

#define C_OO_IN(ret, type, function, ...)       ret (* function ) (struct type##_struct *my, __VA_ARGS__);
#define C_OO_OUT(ret, type, function, ...)      ret type##_##function (struct type##_struct *my, __VA_ARGS__);

#define C_OO_PNEW(type, instance)\
        instance = ( type *) malloc(sizeof( type ));\
        memcpy(instance, & type##__prototype, sizeof( type ));

#define C_OO_NEW(type, instance)\
        type instance;\
        memcpy(&instance, & type ## __prototype, sizeof(type));

#define C_OO_DELETE(instance)\
        instance->dispose(instance);\
        free(instance);

#define C_OO_INIT(type)         void type##_init (struct type##_struct *my){return;}
#define C_OO_DISPOSE(type)      void type##_dispose (struct type##_struct *my){return;}
#define C_OO_EQUAL(type)        char type##_equal (struct type##_struct *my, struct type##_struct *yours){return 0;}
#define C_OO_COPY(type)         struct type##_struct * type##_copy (struct type##_struct *my, struct type##_struct *from){return 0;}
0

I like the typeof() operator. It works like sizeof() in that it is resolved at compile time. Instead of returning the number of bytes, it returns the type. This is useful when you need to declare a variable to be the same type as some other variable, whatever type it may be.

typeof(foo) copy_of_foo; //declare bar to be a variable of the same type as foo
copy_of_foo = foo; //now copy_of_foo has a backup of foo, for any type

This might be just a gcc extension, I'm not sure.

Eyal
  • 5,728
  • 7
  • 43
  • 70
0

Use NaN for chained calculations / error return :

//#include <stdint.h>
static uint64_t iNaN = 0xFFF8000000000000;
const double NaN = *(double *)&iNaN; // quiet NaN

An inner function can return NaN as an error flag : it can safely be used in any calculation, and the result will always be NaN.

note : testing for NaN is tricksy, since NaN != NaN... use isnan(x), or roll your own.
x!=x is mathematically correct if x is NaN, but tends to get optimised out by some compilers

  • Rather then casting hex constants, I prefer to get NaN by nonsignalling floating division of zero by zero. – ulidtko May 26 '11 at 02:27
0

The often forgotten %n specifier in printf format string can be quite practical sometimes. %n returns the current position of the imaginary cursor used when printf formats its output.

int pos1, pos2;
 char *string_of_unknown_length = "we don't care about the length of this";

  printf("Write text of unknown %n(%s)%n text\n", &pos1, string_of_unknown_length, &pos2);
  printf("%*s\\%*s/\n", pos1, " ", pos2-pos1-2, " ");
  printf("%*s", pos1+1, " ");
  for(int i=pos1+1; i<pos2-1; i++)
    putc('-', stdout);
  putc('\n', stdout);

will have following output

Write text of unknown (we don't care about the length of this) text
                      \                                      /
                       --------------------------------------

Granted a little bit contrived but can have some uses when making pretty reports.

Patrick Schlüter
  • 11,394
  • 1
  • 43
  • 48
0

How about using while(0) inside a switch so you can use continue statements like break :-)

void sw(int s)
{
    switch (s) while (0) {
    case 0:
        printf("zero\n");
        continue;
    case 1:
        printf("one\n");
        continue;
    default:
        printf("something else\n");
        continue;
    }
}
Colin King
  • 41
  • 1
-1

In Visual Studio, it is possible for you to highlight your own defined types.

To do that, create a file called "usertype.dat" in the folder "Commom7/IDE". The contents of that file shall be the types you want to highlight. For example:

//content of usertype.dat

int8_t
int16_t
int32_t
int64_t
uint8_t
uint16_t
uint32_t
uint64_t
float32_t
float64_t
char_t
Renan Greinert
  • 3,376
  • 3
  • 19
  • 29