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
Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Is a difficulty a number that can meaningfully be incremented? Or a discrete bag of possible states? If incrementing it is actually meaningful, you might want to use an int or uint8_t or whatever.

This library is cool:
https://github.com/aantron/better-enums

Also easy troll but I am triggered by m_ followed by a capital letter.

Adbot
ADBOT LOVES YOU

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
You might want to try out clang as a replacement compiler. Even if you still mainly use g++, running it through clang when you get a tough error might help - I know they've put a lot of effort into that.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Can you pass a token when you register for the callback that you get back when it's called? That's often has these sorts of libraries let you do things like that, but I've never used this one.

EDIT: Oh, just remove the &, method is already a pointer. The above matters if the same callback function is used in multiple places, like they're nested or something and only slow in some cases. If the function address is enough, it's just your types that are wrong.

Jeffrey of YOSPOS fucked around with this message at 23:15 on Aug 3, 2017

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

b0lt posted:

Member function pointers are not regular pointers. On many ABIs, they're a struct that has a vtable offset and a this pointer offset.

Oh ugg...it didn't occur to me that it was a member function pointer. Presumably he doesn't care which instance? Isn't this a C API which needs a proper function pointer? Maybe that's just always gonna be his thunk....ugg.

I don't think the token would require patching all over the place, at least not if libev itself supports it. Log a backtrace and the id whenever something registers for a callback, print the id in the same place you call gettimeofday.

At the end of the day, you have the value you need, in the worst case you can print it byte by byte in a union with a character array, or as two pointers if that's right. Nonportable but...I don't think that matters in this case.

Jeffrey of YOSPOS fucked around with this message at 23:54 on Aug 3, 2017

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
I assumed the software wasn't easy to just run your own personal instance of, which is why he didn't want to do hacky poo poo like turn off -Werror for his debug build.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

underage at the vape shop posted:

It throws errors at me
We really can't help if you don't give details here.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Can you post your code? It's hard to tell from just that though maybe I just don't remember common scanf pitfalls.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Subjunctive posted:

Why do they even let beginners use C?
because you aren't allowed to use cool abstractions until you can build them yourself :colbert:

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
C is like portable machine code. The, uhh, register allocator isn't a good intro lesson I'm afraid.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Array types have a few niche uses, I know you can use them if you wanna treat a single block of memory as a 2d array. (Cast a pointer to a pointer to an array of one dimension, index it with two indices to read it as an array.)

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

rjmccall posted:

Parameters declared to have array type are always actually pointers, regardless of whether the array has a bound. The bound is completely meaningless unless, in C99, the bound is declared as static (nobody knows you can do this), in which case it's a guaranteed (on pain of U.B.) lower bound on the size of the array.
Haha wow and here I was thinking I knew all of the various and sundry uses of "static". This one is bizarre but...okay.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Pointers to arrays are cool. You can't dynamically allocate 2d arrays unless you either use them or are okay with an extra layer of indirection.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Indeed - also NULL is a pointer-sized binary 0. (Not sure if this is actually platform-dependent but, anywhere that counts.)

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Is rolling your own pool allocator really all that different from using malloc? What is the purpose of the restriction?

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

xgalaxy posted:

Fun fact:
Doom 3 vanilla statically allocated a large array and gave out memory chunks from that.
It did no dynamic memory allocation.
It's not like malloc is magic, this is mostly what it does itself, under the hood. Dynamic memory allocation is the answer to the question "What if I want some number of things but I don't know how many until runtime?". Yes, you can reimplement it yourself and encode program-specific assumptions into your version but...you aren't really avoiding dynamic allocation, you're just writing your own and avoiding using the built-in version.

Like...the big outstanding question is really just "what happens when you free an object?" in the context of doom 3. They have to keep track of which of their objects have been allocated already, and which ones are given back. That is, unless you can't free at all and they have a hard cap on the max number of objects of a given type that can be allocated.

EDIT: Not saying pool allocating isn't useful - it's faster if you only have a few object types than fully-general allocation, and maybe you can pre-run some of your constructors and all that, at least the first time, and it likely will reduce fragmentation, but....it's still just a dynamic allocator. I could see that last one being a big issue for old-school doom when machines were quite memory-limited.

If the reason you aren't allowed to malloc is that it can fail at runtime and you're writing code that really can't fail, you're committing a serious error by writing your own dynamic allocator and using that to work around it. You're still going to crash when you run out of space and fail to handle that case, and you're probably not going to do as good a job as the libc authors at doing so gracefully.

Jeffrey of YOSPOS fucked around with this message at 23:29 on Nov 1, 2017

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

roomforthetuna posted:

Ehhh, if you're running alongside other things then allocating your own space at startup that's as big as you'll ever use is more resilient to mid-run failure than dynamic allocation that can fail because some other program ate all the memory.
Two different kinds of "when you run out of space", only one of them is under your control.
But I do agree that using libc dynamic allocation is just fine for most use-cases and games that rewrite their own dynamic allocation that isn't comprised of pools of same-sized objects are basically being dumb.

I don't think these cases are that different. You still have to check for and handle failure at each place that you do your allocation.

At least on linux, you can tell malloc not to give memory back to the system with a simple toggle option, and preallocate that way. Then you don't have to bother writing your own object pool allocator with a free list or whatever unless you need the latency or lack of fragmentation it would provide. (Both versions can still fail due to over-commitment and paging to disk. There is almost certainly some way to turn this off on a system level but it may not be up to your program.)

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

xgalaxy posted:

Every game I've worked on thats been in C/C++ uses some form of linear allocators aka bump allocators almost throughout the entire code base. You can have one or several that exist for a frame, some that exist for a level or scene, etc. It scopes the life time of objects allocated from those things to those specific life times. "Allocating" from these and "Freeing" from these are markedly faster than using new/malloc & delete/free. No comparison in speed really. In triple AAA you would be stupid not to be using these. Indie games.. who gives a poo poo, you won't be stressing the system on those kinds of games.

And the linear allocators don't need to be homogenous. You can allocate different types from them.. although that limits your optimization space if you need to squeeze out even more performance.

I've used something very similar to this in the past:
https://www.slideshare.net/DICEStudio/scope-stack-allocation
This is fine but you wouldn't call using one of these "not using dynamically allocated memory", would you? I think it violates the spirit of the request even if it's cool.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Rocko Bonaparte posted:

The issue is speed in emulation. Doing a dynamic memory allocation increases the run time by orders of magnitude, and turns seconds into minutes, compounded hundreds of times.

An alternate scheme for the state machine example would be to reserve some number of bytes to store the two largest states and just flip between those as I transition states.

I think wonder if I could have some general purpose templates or macros to put a family of objects into a list that could ultimately be resolved compile-time but without having to remember to add an instance of the new class into the container each time one is written.

Yeah a state could just be an enum and you could have a static array indexed by it if you needed to. My point was really that you should try and find ways to genuinely not need a variable amount of memory, not try to work around it by writing your own Technically Not Malloc. I'm not disputing the value of pool allocators for other reasons but it's not what I think of as avoiding dynamic allocation. That alternative scheme is more what I had in mind if that is the goal.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Twerk from Home posted:

I'm taking over maintenance of a small C++ codebase, and it doesn't have an internally consistent code style. I've used JIndent previously for Java codebases, and am a big fan of Prettier on the js side.

Is clang-format a good tool to use here, or should I buy a JIndent license? I'm looking for something opinionated and just formats code and doesn't make me think. There's no specific style requirements, so I'm probably just going to reach for clang-format's google or LLVM presets and use those.
I would probably just ensure style is consistent within any given file and preserve your change history for each line, assuming there's been version control. clang-format is fine if that's what you want to go with, at least for an initial run. After that I might have a go at setting a style standard that is a bit less stringent though - I'm a big fan of overriding any style guideline if it makes a given piece of code look better.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
this is america, speak ascii

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
You could do:
code:
std::move(b.begin(), b.end(), std::back_inserter(a));
edit: assuming you want to move the elements, use std::copy if you don't know if you can

Jeffrey of YOSPOS fucked around with this message at 22:11 on Dec 5, 2017

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Xeom posted:

If I have a pointer pointing to an element in a struct can I then access the struct in some way? Trying to understand the way the Linux kernel does linked lists. As far as I understand, it embeds the nodes into the data types themselves, and the nodes just point to other nodes.

Yes - this is how linux does it. Your list_head is at a fixed offset into the struct, so if you have a pointer to one, you know it's offset and can subtract that and get the struct itself.

Let's assume this list.
code:
struct silly_node {
	int id;
	struct list_head suckers;
	double profit;
};
Linux provides a macro to do this. Given a pointer to the list head, which we'll call "pos", you can get the silly_node itself with:
code:
struct myList *ptr = list_entry(pos, struct silly_node, suckers);
Linux provides other macros for things if like looping through the list. I know this sounds weird/confusing but it's *extremely helpful* in the kernel environment to be able to append something to a linked list without calling malloc.

Jeffrey of YOSPOS fucked around with this message at 01:58 on Dec 6, 2017

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Do you actually make use of values greatly different in magnitude or would fixed point suffice for your code? No worries if it's gotta be completely generic but that's definitely an option in some use cases.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
I'd want to know if they used something that was more "out there" but yeah, sounds like something you just learn per-project. C++ isn't something many industries pick by default any more and the ones who do generally have a specific purpose for it in mind which may well dictate the toolchain used.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Love Stole the Day posted:

So then what do you guys put on your resumes for prior experience? It seems easier to make a resume for getting into Web Development, where you just have to make something using an in-demand library/tool and then apply to jobs that have it in their job requirements. Here, it seems like there's nothing to demonstrate knowledge or experience with... other than prior experience...

Do you just say "I know C++" and hope they take you up on it then try to pass their technical interviews?
I do mostly low-level stuff and what I want to see on a resume is experience in systems programming, with examples of projects worked on. From there I can often reason about what sort of thing the person was doing and follow up on it on a phone interview. A combination of being able to talk specifics about your prior projects and what you personally did, and pass (difficult) technical interviews will do it. Sometimes if a company is unsure that you know your stuff they'll have you take an online C++ test or something before bringing you in.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Love Stole the Day posted:

Sure this makes sense for what to do during phone interviews, but I was actually asking about what comes before that point: specifically, what you put on that resume to actually get to that phone interview. Do you just put "C++" on your resume and then you hope that you don't get Black Hole'd so that you can actually talk to a human being about your experience with the language?

Talk about projects that you've done using C++ and you can say specifically "in C++" in the description if you'd like. I look for a cluster of related things including not only the language C++ but also low-level computer systems knowledge in general. If I were instead at a game company I might look for game programming projects instead. I don't know how it works at really big companies but our resume screeners read the project descriptions and aren't just looking for keywords.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Definitely clarify more than that - do you want to end up with an n by 2 array? Maybe say what domain this is for? How is the 2d array going to be used? I kinda feel like that's the sort of thing that you ought to figure out how to piece together on your own, it's trivial if you know how things work and dangerous if you don't. Any reason not to loop through and copying wouldn't work.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Arrays are prove to out of bounds errors, my concern would be that you'd be given a firm rigid way of doing something, and only learn to manipulate that without understanding it. I see C as somewhat portable assembly language and is hard for me to think of it as a language whose abstractions I can trust without knowing how they work all the way.

So like, I suspect some XY problem here - what are you trying to store in a 2d array? How many values are you storing? 20 or 100 are both reasonable answers but you should be able to answer before you write any code.

If you want points on a n by n coordinate grid you want array[n][n]. If you want two arrays of size n, you could use an array[10][2], but I'd probably just use two arrays instead. It might be easier to post a (small) snippet of code and how it's defying expectations if you've already written something.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
*lifts up shirt to show battle scars, man boobs* this is my certification

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
I think it will hurt performance if you use it as a drop in replacement if you ever copy them by value and rely on c arrays degrading to pointers in those cases. If you are writing new code, you can explicitly pass references or pointers around when you want them.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
The line:
code:
markCompareData[xLocData[a]][xLocData[a]];
doesn't do anything, or at least should have no side effects. That would return the value in there. Did you mean to set the values and put something like:
code:
markCompareData[xLocData[a]][xLocData[a]] = '@';
Also, you have xLocData twice in that line...something tells me you mean yLocData. Did you initialize the markCompareData array? I see you initialize something called Location but not that.

The thing I was unclear on was what you meant by "combine two arrays". Being precise matters here because there are 11 ways I can imagine to combine arrays and most of them don't result in a 2d array that's nxn for two size n arrays. I don't really even see what you're combining here, you didn't have arrays to begin with either, you created them to store x coordinates and then y coordinates only to then use those to fill in a 2d array. There's a few things going on there - for one, you could potentially skip the middle man, and just use rand() % 10 with the 2d array, something like this:
code:
for(a=0;a<markCount;a++){
        markCompareData[rand() % 10][rand() % 10] = 'A';
}
This is more clear because it represents what you were doing - you're reading in points to fill in a 2d array with. This doesn't get you a list of the points. It's understandable if you'd like to keep those around, but using two arrays in which each array stores half of one point is...awkward to say the least. If this is just a teaching exercise for you to learn to manipulate arrays, it's fine I suppose. I'm not sure if you've done structs yet but an array of those would be better if that's what you wanted to represent:
code:
struct point {
	int x;
	int y;
};

struct point pointList[15];
for (int i = 0; i < markCount; i++) {
	Location[pointlist[i].x][pointlist[i].y] = '@';
}
e:fb

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Reading and writing to those fields will generate instructions that will mask off only those bits and read/write to them. The bit order within memory is compiler-dependent though, so don't rely on it for a network protocol or something. (In practice if you only have one platform it's probably fine - I'm sure this example is that case given that it's .) So 8 bits will be used for the addr bitfield, that could just be a uint8_t itself. 21 bits are used reserved and not for you to use - nothing you write using this struct will set those bits no matter what. 1 bit is used for the retry field - reading from it will return 1 or 0.

You have to know more about the iic protocol to use it I think but yeah, that looks like a fine message header struct/bitfield example to me.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Yeah the compiler will generate code to do the shifting and write to just those bits. You can just write 1 to nostart. The reason people stick typedefs around structs is so they can declare them with one identifier - in the future you can declare one with just "iic_transfer foo;" instead of "struct iic_header foo;" because you have the typedef around it. It's basically saying "create an alias for struct iic_transfer { unsigned bunchofthings:69; } called iic_transfer.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Also the comment says this:
code:
          bit 0    = Write/Read
          bit 1-7  = Address of device
but it doesn't have a separate field for the addr and the write/read flag. Either that's wrong or I just don't know how iic works but that comment seems odd to me given that.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
please use -fno-strict-aliasing

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
Interpreting a sequence of bytes as a struct is like, C's core competency and gently caress if I'm gonna use a union to do it!!!

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Xarn posted:

No. Use memcpy.
So you get a packet full of structs, your system has already copied it once out of the network card buffer, and you're gonna copy it again instead of interpreting it like the struct it is? Maybe I'm poisoned by my domain but that's a little insane to me in this, the language-for-interpreting-bytestrings-as-structs.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

eth0.n posted:

Casting a pointer to char to a pointer to a struct is not a violation of strict aliasing. This is not where memcpy is needed.
But it seems very easy to require it, no? There's plenty of reasons you might need to actually access it as a character array first and then access it as a struct? Maybe I'm misunderstanding something about aliasing rules but my understanding was that, if you use it and access it as a character array, you cannot also access it as a struct, and thus should turn off the silly option.

Alignment is an issue on some platforms. GCC aligned types and attribute packed can help here, but yeah, the compiler will happily convert "aligned pointers" to normal unconstrained pointers without warning by default, so being careful when using those is warranted. In general you should know your own platform here and minimize unaligned accesses but trying to eliminate them completely is pretty extreme if you're, say, handling a network protocol that sends unaligned integers as part of normal operation.

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS
The behavior isn't undefined if your compiler defines how it will behave - conforming to ISO C in this case makes your code worse, not better. My real answer is that I agree with Linus that, while I understand how the aliasing rules came to be, I think they are boneheaded as written and ought to be worked around if you need to view the same memory in multiple ways. They could have specified the language such that the degradation of aliasing assumptions could be controlled by the user, but they didn't bother doing that. The ISO C spec is not a religious text, you're allowed to question it and I think it'd be irresponsible to manage any large C project without at the very least thinking carefully about discarding the existing aliasing rules, especially if what you're doing involves receiving binary data from external sources.

Casting between pointer types in your function is a good sign that the strict aliasing assumptions are not true within that function, my complaint pretty much would go away if the spec was written such that it gave up its aliasing assumptions once that happened.

Adbot
ADBOT LOVES YOU

Jeffrey of YOSPOS
Dec 22, 2005

GET LOSE, YOU CAN'T COMPARE WITH MY POWERS

Jabor posted:

The fact that the "reinterpret the opaque sequence of bytes as a different type" function is called "memcpy" is an unfortunate historical oddity, but it still does what you're actually trying to accomplish in most cases.

Essentially, you can write correct code that also happens to be optimally fast if your compiler works the way you expect it to, or you can write fast code that is only correct if your compiler works the way you expect it to. So what makes the second one preferable to you, again?
I find it odd to treat fno-strict-aliasing as some mysterious and untrustworthy compiler feature not to be relied upon while memcpy elision is to be taken for granted. If my options are fast, zero-copy code or nothing, silent fallback to the slow version is no consolation prize. As far as I'm concerned, my deliverable is what the compiler outputs when it runs on my code and if that include copies of buffers where it shouldn't, it's wrong. Losing aliasing optimizations in other places is unfortunate here and I'd gladly accept a version of C that lets one specify this stuff explicitly, but that's not the universe we're in as far as I know. (attribute ((may_alias)) sounds interesting, maybe I should use that.) I'm far more trusting of the compiler not to make assumptions about aliasing when I explicitly tell it "don't make assumptions about aliasing" than I am in its ability to figure out that's what I'm doing and do the right thing for me wrt optimizing away a memcpy call.

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