Skip to main content
GameDev.net gamedev.net
🔒 Locked

How do you deal with tons of different same fundamental data types?

Started by Alessio1989 Sep 25, 2015 at 10:14 PM 14 replies 5k views
Original Post
Alessio1989
Alessio1989

Let us stay simple and state I want and need to use a single definition for fundamental types with fixed dimensions. (let's forget about why do Microsoft and the C/C++ standards provides non-fixed size...)

How do you deal with the tons of the Windows data types, the VC compiler data types, and the C/C++ unfixed data types? Do you split into two parts your project, one where you code only with your own defined types (where you do not have any external library includes) and another where you have to deal with the Windows headers or other libraries?

Actually I pretty like to use the cstding fixed-size integers, but every-time a function or a structure except a Windows data type I always check for compatibility through C++-style casts (not C-style casts). It is useless to state how boring and annoying is this.

I was thinking to create an header where using tons of static_assert and check the compatibility of my types with Windows Data types and C/C++ types. But I am not sure about that, since I was to add it in the PCH after the Windows and the C/C++ standard library includes.

So, any advice how to make neat all this is accepted.

"Recursion is the first step towards madness." - "Skegg?ld, Skálm?ld, Skildir ro Klofnir!"
Direct3D 12 quick reference: https://github.com/alessiot89/D3D12QuickRef/
Servant of the Lord
Servant of the Lord

I include , and use the standardized fixed width types: uint64_t, uint32_t, uint16_t, uint8_t, etc...

If your implementation doesn't support that type, then that type won't be defined, afaik.

Typically, I use int or unsigned for general usage, and size_t, uint32_t, etc... to more explicitly indicate my assumptions only when I need the fixed width.

Occasionally I have to talk to other 3rd party libraries that use other formats, and in those situations I try to isolate the additional formats only to the borders of where my code needs to talk to that library.

Alessio1989
Alessio1989

What do you do in a piece of code where you retrieve/pass parameters to/from Windows libraries? Actually I pass my types (or just types) and then I static_cast them from/to windows data types. But this is really annoying.

HappyCoder
HappyCoder
Write wrappers around windows calls. Inside your classes, you will include the windows files and use windows types and functions to perform actions. Outside the class, you are using your own types.

Example


// window.h

#include <windows.h>

class Window
{
    HDC windowDeviceContext;
    HWND windowHandle;
public:
    Window(const std::string& title, int width, int height);
    void SetSize(int width, int height);
    void SetTitle(const std::string& title);
    ...
};

My current game project Platform RPG
Servant of the Lord
Servant of the Lord

I don't deal with Win32 directly, but I do deal with some other third-party libraries with their own types (Qt, GL, and SFML for example).

In those cases, if it makes sense to do so, I do static_cast. That's the appropriate way to convert between two similar data types.

Yea, it can get slightly annoying, but in classes that deal excessively with a third-party library, sometimes it makes more sense to treat that class as an extension to that third-party library, and use that library's third-party types internally or even externally.

Every class basically falls into "My code" or "Extension of that library's code", so either my code only calls into that library in a few isolated places, or it calls into my class that wraps functionality and uses the types internally.

Alberth
Alberth
Keeping 'their' code separate at the edges of 'your' code is also helpful in switching to some other library, if you ever need to do that.
Hodgman
Hodgman

Windows-specific code should always be strongly decoupled/isolated from the rest of your code-base. That's just good cross-platform practice!

Only very small amounts of your game should interact with Windows (or other low-level APIs) directly, and these parts of your game should be isolated behind some nice, easy-to-use interface. The rest of your game (99% of your code) should be all nice and standard and clean and portable :)

Alessio1989
Alessio1989

Yes, I still try to separate my own code with code that directly interact with 3rd party libraries (like win32 APIs). I was wondering if there are some dirty tricks (even preprocessor tricks) to feed my laziness and avoid explicit static_cast et similia.

Another question: is a good practice to "undef" 3rd party data types in the project parts you do not need them? I saw that in the UE source code.

Hodgman
Hodgman

Another question: is a good practice to "undef" 3rd party data types in the project parts you do not need them? I saw that in the UE source code.

Don't include them in the other parts in the first place! IMHO having to attempt to undef stuff is a failing.
I've worked with quite a few engines that put "windows.h" into the PCH, which pollutes every single damn file... IMHO this is a terrible thing to do.
Keep implementations hidden smile.png

I was wondering if there are some dirty tricks (even preprocessor tricks) to feed my laziness and avoid explicit static_cast et similia.

You can make some shorthands...
MyVec4 cast( const TheirVec4& v )
{
  static_assert( sizeof(MyVec4) == sizeof(TheirVec4) );
  static_assert( offsetof(MyVec4,x) == offsetof(TheirVec4,x) );
  static_assert( offsetof(MyVec4,y) == offsetof(TheirVec4,y) );
  static_assert( offsetof(MyVec4,z) == offsetof(TheirVec4,z) );
  static_assert( offsetof(MyVec4,w) == offsetof(TheirVec4,w) );
  return *(MyVec4*)&v
}
^^ It's good practice to always document any assumption that you make with an assertion or compile-time assertion. Here I'm documenting that it's safe to reinterpret cast these two vec4 types smile.png

As for the windows types, many of them are just typedefs, so there's no casting requried, e.g.
BYTE windows = 42;
uint8_t portable = windows;//no cast, because BYTE is an unsigned 8bit integer!
Alessio1989
Alessio1989

Thank you, I was not aware about offsetof macro... So, I will try to create some sort of control checks where I put the Windows headers and since cl.exe do not allows multiple pre-compiled headers, I will split all the work into two projects (which was not the initial intention because I am actually working alone on it).

Alberth
Alberth




I will split all the work into two projects (which was not the initial intention because I am actually working alone on it).
Euhm, how is the number of projects related to the number of people working on it?

The normal reason to make a separate project is to handle code sharing between projects (eg you make a library that you want to use in other projects too), or due to licensing or code support reasons (maybe you make code for special device that not everybody has).

Secondly, why do you need two projects?

It's perfectly fine to include 3rd party header files into the .cpp file, possibly with declaring some classes in the header file to make the compiler happy.

In that way, the "pollution" of the 3rd party definition stays within a few .cpp files, instead of spreading to the entire project.

Alessio1989
Alessio1989

I will split all the work into two projects (which was not the initial intention because I am actually working alone on it).
Euhm, how is the number of projects related to the number of people working on it?

The normal reason to make a separate project is to handle code sharing between projects (eg you make a library that you want to use in other projects too), or due to licensing or code support reasons (maybe you make code for special device that not everybody has).

Secondly, why do you need two projects?

It's perfectly fine to include 3rd party header files into the .cpp file, possibly with declaring some classes in the header file to make the compiler happy.

In that way, the "pollution" of the 3rd party definition stays within a few .cpp files, instead of spreading to the entire project.

Usually it's not related. But I am not working on a "huge" project, and I also like to keep things simple. I am also lazy and I do not like spending much time into VS project settings : p

Since I usually work with a laptop and since I usually need to stay in battery mode only, splitting into two project will allows me to include the winAPI headers into PCH where I need, this will speed up the compilation a lot and deny annoying accurate header-include-tree planning. Finally I really like to abuse the static analysis tools, so compilation time get more important than ever for me.

I know these are not good practice in general, but they should works for me.

Giallanon
Giallanon
@alessio1989 sorry for the downvote, I hit the -1 button when trying to go back to previous page from my phone, it was not my intention to downvote
SeanMiddleditch
SeanMiddleditch

I've worked with quite a few engines that put "windows.h" into the PCH, which pollutes every single damn file... IMHO this is a terrible thing to do.


QFT.

Rage fills me every time I see that happen.

Not only does it pollute the files, but then other team members end up _using_ the bullcrap that's in windows.h, and then when it comes time to port your game to another platform you end up having to rewrite goofy Windows functions for all your platforms (and accept any inefficiencies or the like imposed by trying to wrap a Windows interface around a non-Windows OS' primitives).

If you ever include windows.h from another project-public header, you done goofed.
Sean Middleditch – Game Systems Engineer – Join my team!
Norman Barrows
Norman Barrows

wrapper api's for all 3rd party libs is what i usually end up doing. its rare when you find a lib with an API so clean you couldn't greatly simplify it with a wrapper api.

an example, my wrapper API for directx 9 (PODs and procedural code):

http://www.gamedev.net/blog/1731/entry-2258674-the-z3d-api/

Norm Barrows Rockland Software Productions "Building PC games since 1989"</

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.