Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
Jabor
Jul 16, 2010

#1 Loser at SpaceChem
If you need exact bitwise accuracy across different machines, don't use the built-in trig functions at all. In fact, you probably can't even use the built-in floating point support without a lot of care and attention.

Adbot
ADBOT LOVES YOU

Nalin
Sep 29, 2007

Hair Elf
Yeah, I'm not sure if you can rely on floating point math to be identical between Intel/AMD, or even within different CPU generations of the same company.

Xarn
Jun 26, 2015
If you need guaranteed replicable FP results across all platforms, you need to do everything in software.

If you limit yourself to "reasonable" platforms, you will need to link against an implementation of correctly-rounded math lib, e.g. CRLibm

commando in tophat
Sep 5, 2019
According to various sources deterministic FP should be possible, and at least some games rely on it (e.g. it is mentioned here https://www.factorio.com/blog/post/fff-52). And I'm in the easy territory of that because I only need a single exe to give same results (not multiple compilers, different build settings or different platforms, only one build by one compiler on x64).

Xarn posted:

If you need guaranteed replicable FP results across all platforms, you need to do everything in software.

If you limit yourself to "reasonable" platforms, you will need to link against an implementation of correctly-rounded math lib, e.g. CRLibm

Thanks, I'll try that. Any experience with it? It is bit light on readme, and I need to use it also for at least 2 open-source libraries as well

e: oh dear god, this crlibm is great... cmake refers to file that doesn't exist, after removing it, some files try to include some other file that doesn't exist (and of course it has types that are not in windows, but that is pretty standard and easy to fix). I also tried core-math, and that one is full of gcc specific stuff. And other projects I found don't have cmake files, so I don't hold any hope to make them work

commando in tophat fucked around with this message at 16:20 on Jun 26, 2023

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

commando in tophat posted:

I have this problem that when I run my program on different computers (x64), some results won't be same for same inputs when using "sin" (and probably other trigonometric functions and maybe more). By not same I mean I need them to be identical, not just close enough. Is there something easy that can be done about this? I've noticed that in visual studio in code generation, I have runtime library set to "Multi-threaded DLL (/MD)". This apparently means that it will use whatever is available on user's computer and it can give slightly different results?

1. will this help?
2. if this helps and I one of the libraries I use is closed source, does that mean I'm hosed if they only have their library built with /MD ?

I wanted to ask before I spend my day rebuilding all the stuff. I have some recollection that I've changed between /MD and /MT before, but no idea why was that.

1. /MD makes a multithreaded dll, /MT makes a mulithreaded exe. So probably not.

You probably have /MD and /MT confused with static linking vs. dynamic linking. If you're using math.h/cmath and visual studio, you could static link with the msvcrt dll (which IIRC is where these functions live.) But I don't think this will help either.

I think you just end up with this issue:
https://stackoverflow.com/questions/18060241/different-values-for-sin-on-different-cpus

So I don't think you can just make the assumption that sin/cos/etc. are going to give the exact same result on different CPUs. You would need to find a math lib that makes this guarantee and link against it.

nielsm
Jun 1, 2009



Bruegels Fuckbooks posted:

1. /MD makes a multithreaded dll, /MT makes a mulithreaded exe. So probably not.

No, your output file can be either a DLL or EXE with either of those flags.
/MD means you link the dynamic (DLL) version of the runtime library.
/MT means you link the static version of the runtime library.

The "multithreaded" part means that the runtime library is threadsafe/reentrant, in old versions of the compiler Microsoft also offered singlethreaded versions of the runtime, which presumably could have some performance advantages if your code really does not use multithreading at all. (It does not mean that the compiler will try to multithread your code automatically, it just means that you have the option of using threads if you want.)

There's pros and cons of either choice, but in general you need the same runtime library for all parts getting linked into the same output file.

nielsm fucked around with this message at 17:15 on Jun 26, 2023

Bruegels Fuckbooks
Sep 14, 2004

Now, listen - I know the two of you are very different from each other in a lot of ways, but you have to understand that as far as Grandpa's concerned, you're both pieces of shit! Yeah. I can prove it mathematically.

nielsm posted:

No, your output file can be either a DLL or EXE with either of those flags.
/MD means you link the dynamic (DLL) version of the runtime library.
/MT means you link the static version of the runtime library.

The "multithreaded" part means that the runtime library is threadsafe/reentrant, in old versions of the compiler Microsoft also offered singlethreaded versions of the runtime, which presumably could have some performance advantages if your code really does not use multithreading at all. (It does not mean that the compiler will try to multithread your code automatically, it just means that you have the option of using threads if you want.)

There's pros and cons of either choice, but in general you need the same runtime library for all parts getting linked into the same output file.

ugg yeah i always have trouble with this and look it up every time, and then i read the wrong thing. my bad.

but yeah regardless static linking won't fix this.

commando in tophat
Sep 5, 2019
yeah, I'll just try to make some of the math libraries with correct rounding work. Currently RLIBM looks easiest, the only thing that's missing to build it is "__int128", which apparently is not supported...

Xerophyte
Mar 17, 2008

This space intentionally left blank

commando in tophat posted:

According to various sources deterministic FP should be possible, and at least some games rely on it (e.g. it is mentioned here https://www.factorio.com/blog/post/fff-52). And I'm in the easy territory of that because I only need a single exe to give same results (not multiple compilers, different build settings or different platforms, only one build by one compiler on x64).

Nalin posted:

Yeah, I'm not sure if you can rely on floating point math to be identical between Intel/AMD, or even within different CPU generations of the same company.

This kind of depends. IEEE 754 is fairly strict and most compilers will not do any optimizations like re-ordering operations or doing higher-precision fused instructions that may cause the result to deviate from the standard unless you turn on -ffast-math, /fp:fast, or equivalent. 754 specifically requires that the operations add, subtract, multiply, divide, square root, fused multiply–add, remainder, minimum, and maximum have correct rounding.

As long as you only use those operations and don't enable any untoward optimization flags, you should technically be fine. However, this means that:
- Transcendentals like sin, exp, etc may be inconsistent at the CPU level, as noticed.
- Any SSE or AVX instructions are likewise not consistent, sometimes including ones that are on the IEEE list.
- Any math library you call is almost certainly going to deviate, unless the library is specifically designed to be consistent instead of fast.

You cannot fully solve this by static linking. A static build will still almost definitely call the built-in instructions for transcendentals when they're available, and generally may contain arbitrary platform-specific optimization code paths.

If you need to do this then try to isolate the code that needs to be consistent to be in a small, contained part of your program. Turn off as many optimizations as possible for that section. Do not call external code unless it's a specific library that you 100% trust. I used rational approximations to a few transcendentals the one time I did this, since I neither needed or wanted perfect rounding.


Ideally: don't write code that requires perfectly consistent floating point. It's never necessary, and very rarely preferable to the alternatives. 99% of problems can be solved with inconsistent floating point and an appropriate epsilon, and 99% of the remaining problems with a dip into fixed point. Trying to make your FP operations consistent is unlikely to be the best solution to whatever actual problem you're trying to solve.

pseudorandom name
May 6, 2007

Also, generally speaking, x86 CPUs instructions produce identical results across vendors and revisions -- AMD rather famously produced a CPU that had more accurate transcendental functions than Intel, and had to roll it back to the inaccurate versions because too much code broke.

These days they generally produce bitwise identical results, except the occasional bug where some input values are off by 1 ULP.

commando in tophat
Sep 5, 2019

Xerophyte posted:

Ideally: don't write code that requires perfectly consistent floating point. It's never necessary, and very rarely preferable to the alternatives. 99% of problems can be solved with inconsistent floating point and an appropriate epsilon, and 99% of the remaining problems with a dip into fixed point. Trying to make your FP operations consistent is unlikely to be the best solution to whatever actual problem you're trying to solve.

Well, I'm doing game multiplayer with lockstep, so it is either try to make floating point consistent, or rewrite everything that affects game state to fixed point, which also isn't ideal (this would also need to include scripting language library, which I wouldn't really want to do)

I'm already using /fp:strict and in the past also used controlfp to limit precision on x86, which solves most of issues. I hope replacing transcendentals will solve most of rest. Being 99% similar would still mean I would need to find places where it happens and fix it, because if game differs even tiny bit on two computers, it will eventually (but usually very quickly) desync enough to cause problems. And resyncing lot of stuff defeats the purpose of lockstep (but I still have it for occasional fuckups).

At the very least I don't have to rebuild all libraries from /MD to /MT :unsmith:

Beef
Jul 26, 2004
I'm genuinely curious how you got this far into a peer to peer netcode without coming across a warning about the issue with FP in said netcode.
I'm not a game dev, but it seems a staple of gamasutra and gdc post mortem.

At what rate do you need to add sync frames to make it stable with the current situation?

Nalin
Sep 29, 2007

Hair Elf

commando in tophat posted:

Well, I'm doing game multiplayer with lockstep, so it is either try to make floating point consistent, or rewrite everything that affects game state to fixed point, which also isn't ideal (this would also need to include scripting language library, which I wouldn't really want to do)

I'm already using /fp:strict and in the past also used controlfp to limit precision on x86, which solves most of issues. I hope replacing transcendentals will solve most of rest. Being 99% similar would still mean I would need to find places where it happens and fix it, because if game differs even tiny bit on two computers, it will eventually (but usually very quickly) desync enough to cause problems. And resyncing lot of stuff defeats the purpose of lockstep (but I still have it for occasional fuckups).

At the very least I don't have to rebuild all libraries from /MD to /MT :unsmith:

Just know that controlfp can't adjust precision for 64-bit code as 64-bit code uses SSE2 instead of the x87 FPU. But as long as you configure the rounding and keep making sure nothing else changes it, you should be fine with basic floating point math.

commando in tophat
Sep 5, 2019

Beef posted:

I'm genuinely curious how you got this far into a peer to peer netcode without coming across a warning about the issue with FP in said netcode.
I'm not a game dev, but it seems a staple of gamasutra and gdc post mortem.

At what rate do you need to add sync frames to make it stable with the current situation?

Well, the game is hobby project and not played much (even less multiplayer), and with some early testing I got lucky that everything worked (even now from the limited data I have, it seems to run same as on my computer for 30% of players). I don't have a very good system for resyncing, every few seconds I send some simple checksum between players, and if it is different it resyncs everything, which is in hundreds of milliseconds, but it was intended to resync after some more rare event than something that happens every frame (e.g. in event that something fucks up once or twice per game)

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
Deterministic FP is totally fine, the risks here are way overblown. Avoid x87 (which is grossly obsolete anyway), avoid -ffast-math, and use a consistent implementation of transcendental functions and you'll be golden. SSE/etc arithmetic is totally conformant.

Vino
Aug 11, 2010
Hi I was a professional game engineer in a previous life not so long ago and I'd like to warn you against using deterministic fp in netcode. I've never done it myself but I've been around long enough to hear a lot of horror stories about deterministic floating point networking. Some games have shipped with it but only in spite of it, it being very difficult.

In fact if by lockstep you mean that you're doing peer to peer and waiting for every host to get every other input from all other players I hope you're not doing that either. Your life will be way easier if you make one of those peers the host and have them do authoritative simulation.

The way you get around needing deterministic floating point is by having a correction mechanism. Every frame the server sends the true data to each client, and if a float differs more than a certain amount (pick a small enough value that the player will never notice) then the client re-runs its simulation with the corrected value. That shouldn't take more than a few ms unless you have a very complicated simulation. How are you doing the resync?

Rottbott
Jul 27, 2006
DMC

Vino posted:

Hi I was a professional game engineer in a previous life not so long ago and I'd like to warn you against using deterministic fp in netcode. I've never done it myself but I've been around long enough to hear a lot of horror stories about deterministic floating point networking. Some games have shipped with it but only in spite of it, it being very difficult.

In fact if by lockstep you mean that you're doing peer to peer and waiting for every host to get every other input from all other players I hope you're not doing that either. Your life will be way easier if you make one of those peers the host and have them do authoritative simulation.

The way you get around needing deterministic floating point is by having a correction mechanism. Every frame the server sends the true data to each client, and if a float differs more than a certain amount (pick a small enough value that the player will never notice) then the client re-runs its simulation with the corrected value. That shouldn't take more than a few ms unless you have a very complicated simulation. How are you doing the resync?

For many games, lockstep is the only practical way and it works very well. You're trading bandwidth for latency: you only have to send a tiny amount of network data, but you can't run the simulation ahead and extrapolate other players unless you also have a mechanism to rewind and replay it (quickly) when you receive their true inputs. One player with high latency can therefore slow things down for everyone. That's a good trade though if you have the type of game (like Factorio) where the amount of data which an authoritative server would otherwise have to send to clients would be impractical.

It is hard to do, because you have to find all the places where the game can desync. A game I worked had a system to share checksums of the game state between clients, and whenever a desync was detected each client would send its full game state to the host, which would diff them and tell us which value had diverged on which client (the 'why' was left for us to figure out). It was a lot of effort to write and maintain that debugging code, but necessary. Almost all the desyncs we had were not due to floating point differences - floating point isn't magic, and it will behave in a standard way as long as you do the things previously pointed out in this thread - rather they were due to the good old fashioned evil of global mutable state.

nielsm
Jun 1, 2009



Discussion about the architecture of a game that runs in lock-step: https://github.com/OpenTTD/OpenTTD/blob/master/docs/desync.md
OpenTTD has a strict policy about only integer/fixed point math in the simulation.

Vino
Aug 11, 2010
If you have to run lockstep because your world updates would be too large then doing fixed point only sounds like a reasonable way to proceed, I agree.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
If your world is that big, you might be better off not trying to continuously synchronize every last bit of a dataset that it's physically impossible for the user to observe simultaneously. Instead, focus on what's relevant to the user's current view. You could also isolate trivially deterministic subsystems like a Factorio belt and synchronize only events that impact them, rather than their entire state, while still not needing needing to replicate other more complex and expensive logic across every peer.

commando in tophat
Sep 5, 2019
Update on determinism: it seems I've done it, or at least I hope I did. It runs the same on my intel desktop, 10yo notebook with intel on linux (windows exe through wine), at least two AMD cpus. In the end what was needed was /fp:strict, replacing trigonometric functions, and removing some cpu feature detection in physics library, and avoiding fused multiply add (at least it helps for older cpus)

Strong Sauce
Jul 2, 2003

You know I am not really your father.





I'm starting up (or rather my company I work for) on C++. I have not done C++ since Turbo Borland was still being used at my high school.

We're doing multiplatform right off the bat and using C++17 standards. I believe we're mostly using Clang, except we're also supporting Windows (which I believe is a separate compiler). We do have CMake files now to build out all the platforms we're on, but otherwise... what else? Is there a site that lists compatibility issues between both the compilers I'd have to watch out for, and also between different platforms I should be aware of? As an example, don't use the long modifier (for int) because they're defined differently for windows vs linux.

Sorry to just jump in but the OP hasn't been updated in a while so hopefully not too much of a dumb newb question.

Absurd Alhazred
Mar 27, 2010

by Athanatos
Just be specific about the types you're using (if you want a 32-bit unsigned integer, use uint32_t if your company's using <cstdint>; if they're not, make sure they have something that does the same job), and I think otherwise you should be good. There might be platform-specific libraries but hopefully you can #ifdef inside some wrappers to avoid having to deal with that.

I think the main learning curve for you is going to be new features that are common to all C++17-compliant platforms, like fancy templating tools, lambdas, etc.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today
You can use clang on Windows if you like. Be sure you have CI building and testing on all targeted platforms.

LLSix
Jan 20, 2010

The real power behind countless overlords

Strong Sauce posted:

I'm starting up (or rather my company I work for) on C++. I have not done C++ since Turbo Borland was still being used at my high school.

We're doing multiplatform right off the bat and using C++17 standards. I believe we're mostly using Clang, except we're also supporting Windows (which I believe is a separate compiler). We do have CMake files now to build out all the platforms we're on, but otherwise... what else? Is there a site that lists compatibility issues between both the compilers I'd have to watch out for, and also between different platforms I should be aware of? As an example, don't use the long modifier (for int) because they're defined differently for windows vs linux.

Sorry to just jump in but the OP hasn't been updated in a while so hopefully not too much of a dumb newb question.

If either compiler gives a warning or error and the other doesn't, treat it like a real warning. Most of the new hires I've trained assume that just because it compiled and ran with one compiler it will compile and run with the other one on the other operating system. This is not true. One of your two compilers is probably stricter than the other, and whoever set up your build system may have different compiler flags for the different OSes (this is not a great idea, but is unfortunately pretty common). The best approach is to treat warnings/errors from either compiler as a real issue and address it (I'm a strong proponent of treating warnings as errors to ensure a 0 warning compile).

It is very helpful to have both a windows and linux/unix development environment to help troubleshoot issues and compiler warnings/errors that exist only on one OS.

***

I really like https://en.cppreference.com/w/ as a reference for C & C++. It does a good job of providing in-depth technical details without being as overwhelming as the standards. The cppreference.com site's search tool is terrible but googling cppreference <whatever you need> works pretty well.

vote_no
Nov 22, 2005

The rush is on.

Strong Sauce posted:

I'm starting up (or rather my company I work for) on C++. I have not done C++ since Turbo Borland was still being used at my high school.

We're doing multiplatform right off the bat and using C++17 standards. I believe we're mostly using Clang, except we're also supporting Windows (which I believe is a separate compiler). We do have CMake files now to build out all the platforms we're on, but otherwise... what else? Is there a site that lists compatibility issues between both the compilers I'd have to watch out for, and also between different platforms I should be aware of? As an example, don't use the long modifier (for int) because they're defined differently for windows vs linux.

Sorry to just jump in but the OP hasn't been updated in a while so hopefully not too much of a dumb newb question.

Conan for third-party libraries!

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

LLSix posted:

I really like https://en.cppreference.com/w/ as a reference for C & C++. It does a good job of providing in-depth technical details without being as overwhelming as the standards. The cppreference.com site's search tool is terrible but googling cppreference <whatever you need> works pretty well.
I find if I google std::whatever, cppreference nearly always comes up so I don't have to type it.

UraniumAnchor
May 21, 2006

Not a walrus.

Strong Sauce posted:

I believe we're mostly using Clang, except we're also supporting Windows (which I believe is a separate compiler).

Visual Studio ships with a clang compiler that takes VS compiler flags, so you should have that option potentially as well.

Nalin
Sep 29, 2007

Hair Elf
Any, specifically, cppreference has a page for each language version that shows compiler support.

C++17: https://en.cppreference.com/w/cpp/compiler_support/17

Strong Sauce
Jul 2, 2003

You know I am not really your father.





Thanks for all the info. We actually do have our build system up, but I've been kinda tasked with being the subject matter expert when it comes to debugging our issues and also coming up with best practices for our team to write in C++. For example some people are writing int64_t while others have written long long. So I'm looking around for any guides for that kind of stuff as well. I've seen cppreference.com through my searches but besides using it as a quick reference it seems a bit intimidating to read straight through.

Conan looks pretty interesting and we are using Artifactory/JFrog. They also have a community version where we can run our own instance but i'll have to get permission to deploy that on a server. Right now we're kinda bumbling through our package management. Especially since we have to share our code with other teams.

Are there any other resources I should take a look at? Anything that helps people who haven't done much C++ since before standardization? Thanks for all the tips!

Xerophyte
Mar 17, 2008

This space intentionally left blank
Take a look at the various popular style guides, autoformatters, linters and static analysis tools if you haven't already.

Specific tools:
- EditorConfig is supported by most of the IDEs at this point and is useful for setting basic editing rules for assorted file types, including cmake. You may well have used this for a project in some other language.
- Use clang-format for autoformatting. Try to not stray too far from one of the preset styles. Skimming through the linked styles and noting the commonalities is probably a reasonable way to get an overview for what's considered good.
- clang-tidy does assorted linting and static analysis. It can do autofixes for many minor style problems and similar. In a lot of IDEs it is the backing API for the assistance features.
- clang further lets you build with support assorted heavier duty dynamic analysis tools: MemorySanitizer, AddressSanitizer, ThreadSanitizer, etc. These can be very useful to detect specific classes of otherwise hard to find errors, but they're probably not the first thing you set up automation for.

Since there's no agreed upon common style for the language* there tends to be more holy wars about minor things like case, indents, braces, spaces, etc. I don't really have a horse in the style race, but some styles have better tooling than others. Some fields will have specific further requirements, e.g. I work in automotive computer vision and automotive has its own sets of extra-restrictive coding standards that I must adhere to.

On package management, include external dependencies as source and build them with the main project when reasonable. Building everything you need together saves you from all manner of fun package coordination issues. When it's reasonable depends on the size of the dependency, and how complicated it is to build. Conan is almost certainly the package management solution to go for in a greenfield project and artifactory should support it faik.

* The Core Guidelines are a semi-official attempt. They're mostly good, but have some issues. I've not worked somewhere that tried to adopt the core guidelines so I don't really know how well they work in practice.

nielsm
Jun 1, 2009



Xerophyte posted:

On package management, include external dependencies as source and build them with the main project when reasonable. Building everything you need together saves you from all manner of fun package coordination issues.

If you do this, make sure you have a plan for keeping up with upstream.

Nalin
Sep 29, 2007

Hair Elf

Strong Sauce posted:

For example some people are writing int64_t while others have written long long.

Since you are trying to make things work on multiple platforms, definitely don't use raw types like long long.

https://en.cppreference.com/w/cpp/language/types

There are some platform differences in the width of fundamental types. Save yourself the future trouble and just get everybody to use the <cstddef> and <cstdint> types (uint16_t, int64_t, size_t, ptrdiff_t, etc).

You don't want to be hand rolling your own data serialization like a boss and suddenly learning that somebody used long somewhere. Or finding out somebody did pointer arithmetic using ints.

Xerophyte
Mar 17, 2008

This space intentionally left blank
Note that int remains ubiquitous for situations where you just need the platform's most convenient integer to do some arithmetic. This is generally fine, you can't rely on signed overflow so getting a wider than expected type shouldn't hurt you.

You'll still want to use int32_t when you know you require specifically 32 bit integers, like for serialization. You should also prefer uint32_t over unsigned in general. Unsigned values are mainly used when the intended semantics are "packed bytes" so if you want 4 packed bytes then use the type that is explicitly "4 packed bytes".

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Xerophyte posted:

Note that int remains ubiquitous for situations where you just need the platform's most convenient integer to do some arithmetic. This is generally fine, you can't rely on signed overflow so getting a wider than expected type shouldn't hurt you.

You'll still want to use int32_t when you know you require specifically 32 bit integers, like for serialization. You should also prefer uint32_t over unsigned in general. Unsigned values are mainly used when the intended semantics are "packed bytes" so if you want 4 packed bytes then use the type that is explicitly "4 packed bytes".

Don't forget uint_fast16_t and friends.

Ralith
Jan 12, 2011

I see a ship in the harbor
I can and shall obey
But if it wasn't for your misfortune
I'd be a heavenly person today

leper khan posted:

Don't forget uint_fast16_t and friends.

No, please do forget those.

Xarn
Jun 26, 2015

Ralith posted:

No, please do forget those.

TheSkeletonMan
Feb 24, 2011

leper khan posted:

Don't forget uint_fast16_t and friends.

The fastest uint_fast*_t is uintptr_t (usually)

repiv
Aug 13, 2009

that got me curious how those fast types are actually defined (on x64 at least)

fast8 -> u8 on the big three compilers
fast16 -> u32 on msvc, u64 on clang/gcc
fast32 -> u32 on msvc, u64 on clang/gcc
fast64 -> u64 everywhere of course

microsoft apparently disagrees

Adbot
ADBOT LOVES YOU

LLSix
Jan 20, 2010

The real power behind countless overlords

I just want to share my pain.

A few minutes ago I saw production c headers without include guards for the first time in my life. It's an easy fix, but why? How? What were the people who wrote this thinking?

Before you ask, no, no #pragma once either, just nothing at all.

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply