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
JawKnee
Mar 24, 2007





You'll take the ride to leave this town along that yellow line
To make things weirder the second call to GetOpenFileName works fine when the OFN_EXPLORER flag is removed. That obviously isn't a good solution because the old-style looks like garbage.

Adbot
ADBOT LOVES YOU

b0lt
Apr 29, 2005

ShoulderDaemon posted:

I don't know about "no" overhead. It'll probably compile to a type with sizeof(poop) == 1 and will hopefully never actually generate loads or stores to that byte, which is as little overhead as C++ allows, though.

Literally any compiler worth using will compile a zero capture lambda to have zero overhead compared to a standalone C function. It's basically the easiest optimization you could possibly do.

Beef
Jul 26, 2004
Pitching in on the lambda side. It's not just that it will typically not have overhead, it can trigger additional compiler optimizations.

Small anecdote. I changed an inner-loop find() function into a find<iter_N>(). The call sites were then changed to ask, store and call a lambda, instead of directly calling the old find(). Performance improved dramatically. a) The compiler could do a lot more aggressive optimizations, because it had a lot more information available statically. It wasn't just the iter_N template argument, but just that it could infer stuff because only one call site was calling a certain lambda instantiation. b) Duplicating the instruction-memory used was definitely worth it for the improved branch prediction alone. This would have worked just as well for plain function pointers on specializations though, but it would have been a lot harder to write.

High Protein
Jul 12, 2009

JawKnee posted:

To make things weirder the second call to GetOpenFileName works fine when the OFN_EXPLORER flag is removed. That obviously isn't a good solution because the old-style looks like garbage.

It's a long shot (and doesn't explain why the first call works), but try initializing COM with CoInitializeEx.

JawKnee
Mar 24, 2007





You'll take the ride to leave this town along that yellow line

High Protein posted:

It's a long shot (and doesn't explain why the first call works), but try initializing COM with CoInitializeEx.

That appears to have fixed it, but I have no idea why. It doesn't seem to matter if I use COINIT_APARTMENTTHREADED or COINIT_MULTITHREADED either.

Thanks though!

sarehu
Apr 20, 2007

(call/cc call/cc)

b0lt posted:

Literally any compiler worth using will compile a zero capture lambda to have zero overhead compared to a standalone C function. It's basically the easiest optimization you could possibly do.

Wouldn't a standard C function have worse overhead than a 1-byte object that gets ignored while a direct function call gets executed? It's an indirect function call versus (on amd64) a register going unused.

nielsm
Jun 1, 2009



JawKnee posted:

That appears to have fixed it, but I have no idea why. It doesn't seem to matter if I use COINIT_APARTMENTTHREADED or COINIT_MULTITHREADED either.

Thanks though!

It fixes things, because to Windows shell (since Windows 95) is built on COM, and COM can't work correctly if you don't explicitly initialize it on every thread that will potentially touch something COM. The File Open dialog effectively embeds an Explorer view, and so is very dependent on COM.

I think the rule of thumb is that, unless you have a specific reason to use a multi-threaded apartment, you should initialize COM for single-threaded apartment ("apartment threaded").

pseudorandom name
May 6, 2007

You probably have a somewhat broken shell extension installed that assumes that somebody has already called CoInitialize on the current thread before it gets instantiated.

csammis
Aug 26, 2003

Mental Institution

pseudorandom name posted:

You probably have a somewhat broken shell extension installed that assumes that somebody has already called CoInitialize on the current thread before it gets instantiated.

That would be my guess too. Poorly written shell extensions can wreak all sorts of havoc at unexpected times.

I know that you said you got it fixed but since you said you don't normally do Windows programming, here's how you'd deal with debugging a crash like this in Visual Studio:

The output you posted says that there was an error 0xC0000005: Access violation. This might be as simple as a null pointer deference. The debugger can catch the error and break but you have to tell it to do that specifically. I don't have a copy of VS in front of me but if you go to Debug -> Exceptions... there should be a box to check which has this error code. Run it in Debug again and it should break when an access violation occurs. If it's not in your code you might get a mess of disassembly, but if it's in Microsoft code then you can load symbols for the DLL in question. Go to Debug -> Modules and right-click on the DLL in which the error occurred (in this case shell32.dll), select Load Symbols. That will tell VS to grab the debugging symbols from the Microsoft symbol servers and you should end up with the actual code.

JawKnee
Mar 24, 2007





You'll take the ride to leave this town along that yellow line

csammis posted:

That would be my guess too. Poorly written shell extensions can wreak all sorts of havoc at unexpected times.

I know that you said you got it fixed but since you said you don't normally do Windows programming, here's how you'd deal with debugging a crash like this in Visual Studio:

The output you posted says that there was an error 0xC0000005: Access violation. This might be as simple as a null pointer deference. The debugger can catch the error and break but you have to tell it to do that specifically. I don't have a copy of VS in front of me but if you go to Debug -> Exceptions... there should be a box to check which has this error code. Run it in Debug again and it should break when an access violation occurs. If it's not in your code you might get a mess of disassembly, but if it's in Microsoft code then you can load symbols for the DLL in question. Go to Debug -> Modules and right-click on the DLL in which the error occurred (in this case shell32.dll), select Load Symbols. That will tell VS to grab the debugging symbols from the Microsoft symbol servers and you should end up with the actual code.

Unfortunately I did only end up with a load of disassembly despite loading the symbols for shell32.dll, thanks for the advice though.

nielsm posted:

It fixes things, because to Windows shell (since Windows 95) is built on COM, and COM can't work correctly if you don't explicitly initialize it on every thread that will potentially touch something COM. The File Open dialog effectively embeds an Explorer view, and so is very dependent on COM.

I think the rule of thumb is that, unless you have a specific reason to use a multi-threaded apartment, you should initialize COM for single-threaded apartment ("apartment threaded").

Hmm, okay. How would the initial open have gone through at all then?

csammis
Aug 26, 2003

Mental Institution

JawKnee posted:

Hmm, okay. How would the initial open have gone through at all then?

If the guess about the shell extension pans out it might be not be pairing CoInitialize / CoUninitialize correctly. It could be that COM gets initialized on the first call through GetOpenFileName, then gets torn down, but does not get reinitialized on the second call thus causing the crash.

e: this is a total guess on my part

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!

Slurps Mad Rips posted:

a lambda does not a std::function make. Each lambda is its own unique type as if you had written a C++03 function object. There is no overhead for declaring a lambda beyond any captures you make.
Yeah, sorry, I was a bit vague and short with what I meant there. Here is a better explanation.
code:
#include <functional>
#include <stdio.h>

class Poop {
 public:
  void f(std::function<void()> c) {
    printf("std::");
    c();
  }
  void f(void(*c)()) {
    printf("c::");
    c();
  }
};

int main() {
  const char *fart = "fart\n";
  auto x = +[]() {printf("butt\n");};
  auto y = [fart]() {printf(fart);};
  Poop p;
  p.f(x);
  p.f(y);
}
Removing the + from this code makes it not compile, because the function call doesn't know whether to use the std::function version or the function pointer version of f. Given the choice, in a critical piece of code, assuming you don't need to bind anything, you'd probably prefer to go with the function pointer because of the overhead of std::function.

eth0.n
Jun 1, 2012

roomforthetuna posted:

Yeah, sorry, I was a bit vague and short with what I meant there. Here is a better explanation.
code:
...
Removing the + from this code makes it not compile, because the function call doesn't know whether to use the std::function version or the function pointer version of f. Given the choice, in a critical piece of code, assuming you don't need to bind anything, you'd probably prefer to go with the function pointer because of the overhead of std::function.

This is a somewhat contrived example; the "normal" way to do callbacks in C++ is:

code:
template<typename Callable>
void f(Callable op) {
    printf("generic::");
    op();
}
This code can take either of your x or y, but also:

code:
auto z = [](){ printf("shart\n"); };
p.f(z);
This code is likely faster than using a function pointer, since the Callable can easily be inlined, and even if it isn't, will compile to a normal call, not a variable-target call.

If f() has to be written your way, then yes, a function pointer would be slightly faster, since the std::function would probably just be a function pointer plus a flag that gets tested on each call. But its hard to imagine why writing f() that way would be a good idea. I guess if it absolutely can't be a template for some reason?

Plorkyeran
Mar 22, 2007

To Escape The Shackles Of The Old Forums, We Must Reject The Tribal Negativity He Endorsed
All of the implementations of std::function have a "small function optimization" that avoids a heap allocation for sufficiently small things being boxed, so in that case (assuming that the compiler doesn't inline it all out of existence) you're just trading a virtual call for an indirect call. If there's actually a measurable gain in performance from that, then you almost certainly want to adjust things to make it inlinable anyway, as that has a much more dramatic benefit.

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!

eth0.n posted:

If f() has to be written your way, then yes, a function pointer would be slightly faster, since the std::function would probably just be a function pointer plus a flag that gets tested on each call. But its hard to imagine why writing f() that way would be a good idea. I guess if it absolutely can't be a template for some reason?
Yeah, things not being a template is an Important Thing quite often, to my annoyance, in a codebase I frequent.

So, outside of this contrived but unfortunately real situation, when would you want to use a +[] lambda?

Edit: I guess maybe when you're passing it to a function that takes a function pointer, just to make it explicit so nobody comes along later and thinks they can bind a variable there, would be one use, but there must be something better than that.

ShoulderDaemon
Oct 9, 2003
support goon fund
Taco Defender

roomforthetuna posted:

Yeah, things not being a template is an Important Thing quite often, to my annoyance, in a codebase I frequent.

So, outside of this contrived but unfortunately real situation, when would you want to use a +[] lambda?

Edit: I guess maybe when you're passing it to a function that takes a function pointer, just to make it explicit so nobody comes along later and thinks they can bind a variable there, would be one use, but there must be something better than that.

There really isn't much other point. Keep in mind that +[] lambdas aren't a "real" syntax construction, they're just a side effect of a non-closure lambda decomposing to a function pointer when you apply unary +. Sometimes you have to work with C-style function-pointer APIs, and sometimes when you are using one of those it's handy to use a lambda, and in that case adding the + is a convention that other C++ programmers will either recognize as "you can't use a real closure here", or will be confused by and will look up, hopefully resulting in the same outcome.

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!

ShoulderDaemon posted:

There really isn't much other point. Keep in mind that +[] lambdas aren't a "real" syntax construction, they're just a side effect of a non-closure lambda decomposing to a function pointer when you apply unary +. Sometimes you have to work with C-style function-pointer APIs, and sometimes when you are using one of those it's handy to use a lambda, and in that case adding the + is a convention that other C++ programmers will either recognize as "you can't use a real closure here", or will be confused by and will look up, hopefully resulting in the same outcome.
Aha, thanks. The best thing about this topic is that when you google search about it, the best result is a stackoverflow question asking "what sorcery is this?"

Tarion
Dec 1, 2014

roomforthetuna posted:

Yesterday I learned of this cool thing:
code:
auto poop = +[]int(int butts) {return butts * 2;}
That unusual + makes poop a simple old-school function pointer rather than a std::function with the overhead that entails. Neat!

I didn't know that the non -> syntax for functions was allowed for lambdas... or at least I think that's what the int means between the [] and the (...

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!

Tarion posted:

I didn't know that the non -> syntax for functions was allowed for lambdas... or at least I think that's what the int means between the [] and the (...
That was probably just a mistake on my part.

ullerrm
Dec 31, 2012

Oh, the network slogan is true -- "watch FOX and be damned for all eternity!"

nielsm posted:

It fixes things, because to Windows shell (since Windows 95) is built on COM, and COM can't work correctly if you don't explicitly initialize it on every thread that will potentially touch something COM. The File Open dialog effectively embeds an Explorer view, and so is very dependent on COM.

I think the rule of thumb is that, unless you have a specific reason to use a multi-threaded apartment, you should initialize COM for single-threaded apartment ("apartment threaded").

It's more that you should init STA if you're touching Windows shell
/UI code. (The STA serialization is actually achieved by running a message pump, which allows certain shortcuts/assumptions to be made.)

PS. Love the cabin
Dec 30, 2011
Bee Lincoln
I have a 320x240 image mapped to an array of 8x8 tiles which store ascii keycodes for an on screen keyboard.

lovely example:


If I have a touch event in the E region, how can I find neighbouring tiles with the same key code?
The idea is to invert the colours in that region to give feedback that the button has been pressed.

I could always go through the entire array for matching tiles but that's probably a bit too lazy for my liking.

eth0.n
Jun 1, 2012

PS. Love the cabin posted:

I have a 320x240 image mapped to an array of 8x8 tiles which store ascii keycodes for an on screen keyboard.

lovely example:


If I have a touch event in the E region, how can I find neighbouring tiles with the same key code?
The idea is to invert the colours in that region to give feedback that the button has been pressed.

I could always go through the entire array for matching tiles but that's probably a bit too lazy for my liking.

You could add a pointer to each cell which points to the "next" cell in the same region, such that if you follow the pointers in turn, and end up back at your starting cell, you know that you've visited all the cells in the region.

But for such a small array, simple iteration like you've said is probably fine, and possibly better, especially if you're only storing a single byte code for each cell currently.

JawKnee
Mar 24, 2007





You'll take the ride to leave this town along that yellow line
depending on how often you're changing the array, and assuming you aren't looking for a range of values, some kind of multi-value hashmap could help, store array locations using the keycodes as keys

PS. Love the cabin
Dec 30, 2011
Bee Lincoln

eth0.n posted:

But for such a small array, simple iteration like you've said is probably fine, and possibly better, especially if you're only storing a single byte code for each cell currently.

Well I suppose the simplest solution is the right one in this case :D
I was worried about it being slow but it's really not that bad.

Popete
Oct 6, 2009

This will make sure you don't suggest to the KDz
That he should grow greens instead of crushing on MCs

Grimey Drawer
Can anyone recommend a GUI library for C? I've been using ncurses to write ASCII games but I'm curios whats out there for creating standalone games that don't rely on a terminal.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

PS. Love the cabin posted:

Well I suppose the simplest solution is the right one in this case :D
I was worried about it being slow but it's really not that bad.

Do the simple thing until a profiler tells you to do something more complex.

nielsm
Jun 1, 2009



Popete posted:

Can anyone recommend a GUI library for C? I've been using ncurses to write ASCII games but I'm curios whats out there for creating standalone games that don't rely on a terminal.

What kind of game, what kind of GUI? And what platforms?

If you just want to open up a window or go fullscreen, and then draw some 2D or 3D graphics, SDL is probably the library of choice. It's rather low level, but there should also be a ton of other libraries to help you do more.

If you want to make big, complex things, consider looking at Unreal Engine 4. It's a gigantic kit that probably has anything you could wish for.

If you want to make nerd-rear end games that look more like a line-of-business application, maybe check out Qt.

Popete
Oct 6, 2009

This will make sure you don't suggest to the KDz
That he should grow greens instead of crushing on MCs

Grimey Drawer
My goal is to create stand alone executables for Linux and Windows. I've been using the ncurses library to make ASCII rouguelike games that run from a terminal but I figure moving towards a platform/terminal independent executable would be a good next step. It doesn't need to be anything fancy at all just a fairly simple windowing library. If it works similar to ncurses that would be fantastic.

JawKnee
Mar 24, 2007





You'll take the ride to leave this town along that yellow line
SDL is crossplatform (I think), there is no standard tool for doing GUIs that is crossplatform though - I just went through trying to do this for an application I was working on.

VVV Sorry I meant standard, not native

JawKnee fucked around with this message at 22:36 on Feb 27, 2016

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

JawKnee posted:

there is no native tool for doing GUIs that is crossplatform though - I just went through trying to do this for an application I was working on.
:confused:
wxWidgets, GTK, Qt, Tk, ...

I've recently learned that packaging GTK programs for non-linux is a huge pain though. wxWidgets is good at looking native on all platforms, so I'd try that first.

feedmegin
Jul 30, 2008

JawKnee posted:

SDL is crossplatform (I think), there is no standard tool for doing GUIs that is crossplatform though - I just went through trying to do this for an application I was working on.

VVV Sorry I meant standard, not native

Well obviously. Platforms are standards. Who would even define a 'standard' cross platform tool?

Qt is awesome btw but it is C++ which is uh not the same as C. Same with wxWidgets.

feedmegin fucked around with this message at 15:00 on Feb 28, 2016

Hughlander
May 11, 2005

I'd argue scaleform is the answer. Flash authoring tools are as standard as can be, and you can run it on anything with a video out...

hackbunny
Jul 22, 2007

I haven't been on SA for years but the person who gave me my previous av as a joke felt guilty for doing so and decided to get me a non-shitty av
I can personally vouch for Qt. It's a really good framework. It does complicate your build slightly, because you need to run an extra tool (moc, Meta Object Compiler) to enable all features relying on type metadata, but QObject and the signals/slots system are really good. Some parts of Qt have been obsoleted by recent changes to the language, but it's still good, and it's always been a pleasure to work with in my experience

Doc Block
Apr 15, 2003
Fun Shoe
If you want just C then I think your options are GTK and, uh... Motif?

Subjunctive
Sep 12, 2006

✨sparkle and shine✨


Tk has C bindings, if we've moved to crazytown.

weird
Jun 4, 2012

by zen death robot
it sounds like they want sdl

Volguus
Mar 3, 2009
I've recently heard about http://nanapro.org/en-us/ . It's modern C++ (not C) but from the examples it looks quite decent. It doesn't seem to be just a wrapper over GTK or other libraries, it looks like it does its own painting.

feedmegin
Jul 30, 2008

Subjunctive posted:

Tk has C bindings, if we've moved to crazytown.

Tk is written in C, you mean. It has TCL bindings ;) It used to be the best way to do open source cross platform GUI stuff in the mid 90s, but yeah, we have better options now.

I guess there's also EFL (the Enlightenment toolkit).

feedmegin fucked around with this message at 12:25 on Feb 29, 2016

Illusive Fuck Man
Jul 5, 2004
RIP John McCain feel better xoxo 💋 🙏
Taco Defender
When you assign a lambda to a c style function pointer, what's the lifetime of things it captures by value? Do they just vanish? Seems like this shouldn't even be allowed.

edit: never mind, I wasn't doing what I thought I was doing

Adbot
ADBOT LOVES YOU

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

feedmegin posted:

Tk is written in C, you mean. It has TCL bindings ;)

The tcl.tk wiki describes the C interface as a "native binding". :shrug:

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