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
pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Why does this work?

C++ code:
// This is actually C but there's only syntax highlighting for C++ I guess?
#include <assert.h>

static void *Something = &Something;

int main(void) {
    assert(Something == &Something);
    return 0;
}
By which I mean these two questions (which might be the same question phrased twice). Why can I take the address of Something when I'm not even finished declaring it? And why does it equal its own address?

I can't figure out what to search for, and flailing wildly through the C99 spec just got me even more lost.

Adbot
ADBOT LOVES YOU

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Suspicious Dish posted:

What if I rewrote your code like this:

Why does this work?

C++ code:

// This is actually C but there's only syntax highlighting for C++ I guess?
#include <assert.h>

static void *Something;

// this is actually possible in some compilers, Google for "gcc
// constructor attribute"
static void CALLED_ON_INIT_BUT_BEFORE_MAIN(void) {
    Something = &Something;
}

int main(void) {
    assert(Something == &Something);
    return 0;
}

So the compiler emits code to initialize the global before main runs. In retrospect, I don't know how else that would work. Thanks!

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

rjmccall posted:

highly informative novel about globals

I read this twice and, just to make sure I get it: my little example program's global pointer falls into the second case. It takes the address of something provably in the same dynamic object, so the compiler leaves in the offset and a note asking the loader to relocate the address. Since this is a tiny executable, the only potential hit comes from adding the slide to the offset, but if it was a larger executable or in a dylib there could be disk reads that, in my example program, would be entirely pointless at the time. The compiler emits no initialization code.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

rjmccall posted:

Exactly right, assuming your tiny program is a relocatable executable. Some platforms don't support relocatable executables, and on others you have to ask for them manually. On Apple platforms, it's the default; you can verify that an executable is relocatable with otool -hv and checking that one of the flags is PIE (for "position independent executable").

Awesome. Thanks a lot for writing all of that up.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Morham posted:

I have a quick question regarding some logic I have written. It's my first C program, and it's a guess the number game in the console. I wrote the following code to prompt the player if they wanted to play again, and to continually do so until they either typed 'y' (121) or 'n' (110).

code:
do								
{
	printf("Would you like to play again? (y/n): ");
	scanf("%s", &input);
}
while (input != 121 && input != 110);
Now when I first wrote this I used an 'OR' ('||') operator in the while condition thinking that would be right since I want it to continue to ask until the player hits 'y' or 'n' however it didn't work. When I replaced it with an 'AND' ('&&') operator it works perfectly. In my mind this operation should continue until input is equal to 121 and 110 at the same time, and since a variable can't hold two values it should never stop executing.

Am I misunderstanding something fundamental about logic here?

What's the difference between
code:
input != 121 && input != 110
and
code:
!(input == 121 || input == 110)

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

GrumpyDoctor posted:

Along these lines, say that - completely hypothetically here - I've been convinced by an internet forum that 1 is superior to 2, but I've got a tiny project (10k loc) all done using style 2 that I'm the only developer on. Is there a good automated way to go through the codebase and switch them, and if so, is doing so worth it?

Just switch code over as you come across it in the course of other excursions into the project.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

pseudorandom name posted:

HFS+ does, but that caused enough problems that APFS doesn't.

And that caused enough problems that APFS now does. I think. https://developer.apple.com/library/archive/documentation/FileManagement/Conceptual/APFS_Guide/FAQ/FAQ.html

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I'd like some general way to return values asynchronously in C++. Currently we either park a thread or, occasionally, take a callback when e.g. making an HTTP request. But I'd prefer to return something rather than nest callbacks endlessly. Something like a Future type. Is there anything like that built into the standard library? Should I consider coroutines? Is there a focused lil library that everyone uses?

This is recent-ish clang (Android NDK and iOS SDK) and we're on C++20 (I could probably bump that if necessary).

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I got the impression that std::future and std::promise block threads, which I was hoping to avoid. Is there some other way to use them like "when this future's done, run this code"?

Coroutines look like what I want, just complicated. I'll give them a shot.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Yeah I'm more looking for the "here's a chunk of code to run when the future's ready" version.

Currently we can end up with dozens of threads all blocked. Possibly unbounded, actually, I'd have to double-check. And there's certainly other ways to stop doing that, I'm hoping this one is the least painful :)

Thanks!

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
Yep more async/await.

It's a pile of C++ that an Android and an iOS app both call into. That pile of C++ in turn can call back out to the platform for database and network operations. A call sequence might be
code:
app.onClickLogIn()
    pile.logIn(user, pass)
        app.doHttp("POST", "/login", params)
            urlSession.fetch(…)
        app.saveUser(user)
            db.transaction(…)
and it's all synchronous. Even though the URL session is async (we stick a semaphore around the platform calls to make it synchronous), the database is async (ditto), and we've gotta get off the ui thread in the first place.

I'd like to change the URL session, database, and topmost (in this case, logIn()) calls to return futures/be coroutines/something. The URL session or database will complete the future on some arbitrary thread and that's ok with me, they've got their own dispatchers and thread pools, I just don't want to park a thread waiting for them to finish.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.

Jabor posted:

In Java you have a ListenableFuture that allows you to get a callback on a particular executor when the value becomes available, which means you're not burning an entire os thread for every single future you're waiting on.

It looks like C++ was considering standardising a future::then() method which would allow much the same thing, but it doesn't seem to have happened for some reason? Maybe they figured that coroutines were a better way to accomplish that goal?

Plorkyeran posted:

std::future is missing then(), which is the thing that actually makes futures interesting and useful and it's kinda pointless as a result. It's relatively easy to roll your own future type which actually is useful.

Woops, missed these. "Where is std::future::then()" is the concise way to ask what I'm going for. Seems like coroutines are the closest?

The platform barrier is handled by Djinni and it has a future that works at that barrier, but I didn't necessarily want to spread Djinni stuff all throughout the C++ code. It seems like a fairly generic future type with a then() though, so maybe it's the right thing to use.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
then() also returns another future for the result of running the closure passed to then(), so it lets you get away from increasingly indented callbacks. I agree it doesn't look super useful with a single call.

And in my case, I have a future type with then() that translates between C++ and Java/Objective-C, so I figure if I can use something similar within C++ it'll be overall easier to follow. (I can't add similarly translatable callbacks without a ton of work.)

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
This discussion makes me think of 0mq. Did anyone ever take/use it seriously? I enjoyed reading their docs but never found a use for it.

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
As someone who likes to understand wtf is going on, C++ is intensely frustrating. But I've gotten to the place where I'm no longer surprised to learn about a new footgun, I'm just disappointed. So yeah I feel for ya op.

Adbot
ADBOT LOVES YOU

pokeyman
Nov 26, 2006

That elephant ate my entire platoon.
I remember more about the couple hours I messed with bazel than the 20 hours I've messed with cmake. Something about cmake is just perfectly designed to slip right off my brain. Makes zero sense to me.

Anyway op cmake is the safe choice. If you try something weird: redo.

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