handmade.network » Forums » Programming mannerisms
debiatan
Miguel Lechón
71 posts
#20780 Programming mannerisms
3 months, 3 weeks ago Edited by Miguel Lechón on March 24, 2019, 4:27 p.m. Reason: Initial post

Do you use some unheard-of personal convention or trick while programming? I would like to hear about them.

I'll start with one of my own.

Sometimes, inside a comment, I want to talk about a distant piece of code. While I might point to that location using some notation based on file names, function names and line numbers, all those descriptors are subject to change. What I do instead is to paste a short random string in both the comment and the target location. Something like this:

1
2
3
4
5
6
7
8
void foo(){ // NOTE: #iexuje
    ...
}

void var(){
    ...
    // TODO: Consider #iexuje
}


Most of the time my use of this trick is a symptom of something wrong with my code that should be solved instead of commented upon (a simple example would be duplicated code), but If I want to postpone fixing the underlying problem, this is the way I make sure it won't escape me. Naturally, I never modify a piece of code that contains one of those random identifiers without looking at the rest of its siblings.

mrmixer
Simon Anciaux
633 posts
#20794 Programming mannerisms
3 months, 3 weeks ago

I use a similar thing by placing "bookmarks" in the code using comments:
1
/* MARK an_indentifier */


Casey's use of renaming a type or function and recompiling to use the error reporting to see every location the type/function is used.

Using a known value in asserts so that if I only have the disassembly I can recognize an assert (I believe I got that idea from Allen Webster).
1
2
3
4
5
/* In C */
#define _assert( expression ) if ( !( expression ) ) { *( ( u32* ) 0 ) = 0xa55ea55e; }

/* In the disassembly */
mov         dword ptr [0],0A55EA55Eh
mmozeiko
Mārtiņš Možeiko
1941 posts / 1 project
#20798 Programming mannerisms
3 months, 3 weeks ago Edited by Mārtiņš Možeiko on March 27, 2019, 4 a.m.

I don't understand why people want to write to NULL pointer. My debug macro looks like this (on MSVC):
1
#define _assert( expression ) if ( !( expression ) ) __debugbreak();

This is trivial to spot in assembly, because it is one byte (0xcc) instruction "int3" which is never generated in middle of functions by normal code. And debugger always stops on it as it thinks it is a breakpoint. I have used this for years, and similar thing works also on gcc/clang on x86 arch.
Telash
Mikael Johansson
99 posts / 1 project
#20802 Programming mannerisms
3 months, 3 weeks ago

I keep ALL my persistent data in a superstruct, that has nested substructs. Then the superstruct is global, and named with just one letter. So I never send data to a function, it just uses the superstruct. I just send index info to the functions, like

enemy_Delete(10); //Deletes the 11th enemy.

And "deleted" in this case just means it gets flagged for reuse.

The biggest obstacle to great software is lack of motivation. Motivate each other!
Instead of reinventing the wheel, we should put chariot wheels on jet planes!
mrmixer
Simon Anciaux
633 posts
#20805 Programming mannerisms
3 months, 3 weeks ago

@mmozeiko I didn't know about __debugbreak(). I used DebugBreak() in the past but that was causing the breakpoint on the wrong line (one line after most of the time). Another reason is that I have 3 "breakpoint" functions and that allowed me to differentiate between them (not that it has ever been useful).

__debugbreak() allows to continue stepping in the code without the need for "set next statement" so that's a win. Thanks.

@Telash Having everything global and accessible from everywhere seems a bit overkill to me. In my opinion, there is value in knowing on what data a piece of code operates.
debiatan
Miguel Lechón
71 posts
#20806 Programming mannerisms
3 months, 3 weeks ago

Telash
Then the superstruct is global, and named with just one letter.


It's funny. I use the underscore character for my global platform API superstruct pointer, which makes calls to the platform layer stand out:
1
2
_->console.print("foo\n")
_->file.read("fname")


In case anyone is tempted to adopt this convention I should say that I'm not sure my use of the underscore character is legal. I think ANSI C 3.1.2.1 and 4.1.2.1 say it's OK, but the GNU C Library docs say that all globals have external linkage and thus the underscore is off limits.
debiatan
Miguel Lechón
71 posts
#20807 Programming mannerisms
3 months, 3 weeks ago

mrmixer
Casey's use of renaming a type or function and recompiling to use the error reporting to see every location the type/function is used.


This one reminds me of a trick I use to rename symbols across a project by leaning on the compiler. It goes like this:
- rename a symbol (variable, parameter, type, function)
- press 'qq' in vim normal mode to start recording a macro under the letter 'q'.
- press ',,' which is my alias to compile-and-jump-to-next-error, defined like this in my .vimrc:
1
2
  let mapleader = ","
  nnoremap <leader>, :silent make -s -j4\|cc<CR>zv

- enter 'dw' to remove the offending symbol name
- type the new name in insertion mode
- exit insertion mode and press 'q' again to finish the macro
- enter '[email protected]' to run the macro a hundred times, which stops as soon as the compilation succeeds

This approach also works for other rote substitutions, such as change the type of a parameter to be a pointer to its original type and turning all the incorrect '.' into '->'. However, it depends on the ability of the compiler to generate accurate row and column information for compilation errors and is easily confused if the old symbol name appears inside a C macro.
Mr4thDimention
Allen Webster
471 posts / 2 projects

Heyo

#20813 Programming mannerisms
3 months, 3 weeks ago Edited by Allen Webster on March 27, 2019, 10:48 p.m.

In the vein of "change a thing's name to use errors as your to-do list" type tricks, I occasionally get fed up with enums that are switched in disparate locations, and that change often. Instead of trying to get something like a case coverage requirement to work (which might not be appropriate in each case anyway) I just throw in a dummy macro to flag these related locations:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
enum My_Switchable_Thing{
  MySwitchableThing_Foo,
  MySwitchableThing_Bar,
  MySwitchableThing_Booper,
  MySwitchableThing_BoppityBoo,
};
#define my_switchable_thing_version_4

// ...

void do_a_switch(My_Switchable_Thing mst){
    my_switchable_thing_version_4;
    switch (mst){
        case MySwitchableThing_Foo:
        { /* you get the idea*/ }break;
        case MySwitchableThing_Bar:
        { /* you get the idea*/ }break;
        default:
        { do_a_switch(boopers_type_things(mst)); }break;
    }
}


Now I can make sure I reconsider every switch of My_Switchable_Thing by changing the definition of my_switchable_thing_version_4 to my_switchable_thing_version_5.