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
4lokos basilisk
Jul 17, 2008


As I am exploring different ways of creating/processing sound with my computer at the moment, I've decided I want to try playing around with some C++ libraries that deal with this. So I've chosen Portaudio (http://portaudio.com/) and Qt (because I've worked with it in the past) to make some kind of hello world thing.

I've gotten as far as doing the Portaudio tutorial within a Qt-Creator project, which (after adding Portaudio to LIBS in the project file) seems to compile with no problems, however when I try to run it, instead of producing a sound from my speakers like it should when I run the Portaudio example that I've more or less pasted into the IDE, it just displays a X11 terminal window telling me to press RETURN.

So I guess what I need is some sort of guide to show me how would I go about integrating the Portaudio library into my project/code so that it would compile and be generally usable. I'm doing all this on Mac OS X 10.6 by the way.

Adbot
ADBOT LOVES YOU

IratelyBlank
Dec 2, 2004
The only easy day was yesterday
I'm trying to wrap my brain around abstract classes. What I am specifically trying to do is create a dynamic array of abstract objects. My stripped down setup looks like this:

code:
class Student 
{
public:
	virtual double returnAverage()=0;

protected:	
	Student();
	Student(string, string, string);
};


class Math : public Student
{
public:
	Math(...);
	double returnAverage();
};

....


Student * parseStudentInfo(...);
void readInput(..., Student *);

int main()
{	
	Student** students = new Student*[count];
	readInput (in, "test.txt", *students);
}


void readInput(..., Student *students)
{
	students[index] = parseStudentInfo(...);
}

Student * parseStudentInfo(string fname, string lname, string course, string grades)
{
	return new Math(...);
}
I'm getting the error when I try to set students[index] = parseStudentInfo(...). I think my problem is either the return type of the function or the way I am trying to assign the new student in my array. I think the return type is correct because it is returning a pointer to an object instead of an object, so that leaves the students[index] =, but I'm not sure what else would this be since (I think) this is a pointer array of pointers?

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Why are you passing the first element of the array into readInput, instead of a pointer to the first element?

nielsm
Jun 1, 2009



Why are you not using std::vector?

IratelyBlank
Dec 2, 2004
The only easy day was yesterday

Jabor posted:

Why are you passing the first element of the array into readInput, instead of a pointer to the first element?

This must be a mistake on my part, I wanted to pass a reference to the entire array into readInput instead of just a single item. How do I pass the entire array, **students?

nielsm posted:

Why are you not using std::vector?

I am working through a university course in OOP that posts their assignments online in an effort to learn C++ on my own, so the whole point of the program was to avoid STL libraries and do it the hard way to learn from the bottom up.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

IratelyBlank posted:

code:
void readInput(..., Student *students)
{
	students[index] = parseStudentInfo(...);
}
I'm getting the error when I try to set students[index] = parseStudentInfo(...). I think my problem is either the return type of the function or the way I am trying to assign the new student in my array. I think the return type is correct because it is returning a pointer to an object instead of an object, so that leaves the students[index] =, but I'm not sure what else would this be since (I think) this is a pointer array of pointers?

1. You are not telling us what the error is. In this case we can figure it out, but only by reading between the lines. It's always nice to spare people that trouble and just tell us what's going on.
2. Both of the questions above are valid.
3. A pointer to a dynamically-sized array of pointers would have type Student**, which is not the type of students.
4. ETA: you dereference a pointer if you want to work with (or change) the value it points to. You don't need to dereference a pointer just to pass it around as a value.

rjmccall fucked around with this message at 01:41 on Jun 26, 2012

IratelyBlank
Dec 2, 2004
The only easy day was yesterday

rjmccall posted:

1. You are not telling us what the error is. In this case we can figure it out, but only by reading between the lines. It's always nice to spare people that trouble and just tell us what's going on.
2. Both of the questions above are valid.
3. A pointer to a dynamically-sized array of pointers would have type Student**, which is not the type of students.

Sorry, the error is:
Unhandled exception at 0x00c576fb in cpp.exe: 0xC0000005: Access violation reading location 0xcdcdcde9.

on this line:
code:
students[index] = *parseStudentInfo(fname, lname, subject, grades);
I added the * in front of parseStudentInfo or it wouldn't compile.

e: Passing **students instead of *students seems to fix my problem, thanks to everyone.

IratelyBlank fucked around with this message at 01:42 on Jun 26, 2012

nielsm
Jun 1, 2009



IratelyBlank posted:

I am working through a university course in OOP that posts their assignments online in an effort to learn C++ on my own, so the whole point of the program was to avoid STL libraries and do it the hard way to learn from the bottom up.

One of the basic ideas in OOP is wrapping things.
If you don't want to use the STL-provided container classes, then write your own. There is a reason the container class abstraction is commonly used: It makes it much harder to make mistakes like the one you just made.

It's also a good exercise to write your own dynamic array class. In fact, go do that right now.

raminasi
Jan 25, 2005

a last drink with no ice

IratelyBlank posted:

I added the * in front of parseStudentInfo or it wouldn't compile.

e: Passing **students instead of *students seems to fix my problem, thanks to everyone.

I'm really not trying to jump down your throat to just be a dick, but shotgunning asterisks around until it compiles isn't usually a very good way to actually learn anything.

Computer viking
May 30, 2011
Now with less breakage.

Rocko Bonaparte posted:

I find myself spinning a lot on calls to stuff that returns a bool to continue running. I figured it was about time I did something about them because the poll overhead is now sufficiently obnoxious. I could callback to signal the end of the operation but I was hoping not to have to write and implement callbacks every time. I can't think of a way to do it better with, say, Boost. I am using its threading stuff right now, so I do use condition variables in places, and I use the predicate function in there sometimes. Does anybody know anything clever that I might try here? I can only think of stuff using Tasklets or similar, but it wasn't clear to me they put anything like that in the library.

If you don't mind doing it without boost, you could set up a shared struct with one int per flag, and then just check/update that. The idea is that writing an integer to memory is an atomic operation, so you'll never do worse than getting an outdated value - which is fine if you're just waiting for stuff to finish. The polling then becomes something like "while (! flags->thing) {sleep}" - the best-case is just a simple compare.

If you require more than "correct but perhaps old", you'll have to wrap it in a mutex - a bit more expensive; I have no idea how it compares.

Oh, and I've never tried this - so there might be obvious problems I've overlooked.

Edit : you can also set up a bunch of mutexes, lock them in the busy thread at the beginning, and then unlock them again as things proceed. Sleeping on a mutex takes no cpu and wakes you when it becomes available, so that could be decently efficient. (Last time I did anything with locking was ages ago for a toy OS, so uhm - don't trust a word I'm saying.)

Computer viking fucked around with this message at 17:43 on Jun 26, 2012

That Turkey Story
Mar 30, 2003

Computer viking posted:

If you don't mind doing it without boost, you could set up a shared struct with one int per flag, and then just check/update that. The idea is that writing an integer to memory is an atomic operation, so you'll never do worse than getting an outdated value - which is fine if you're just waiting for stuff to finish. The polling then becomes something like "while (! flags->thing) {sleep}" - the best-case is just a simple compare.

This is not true and could fail for any number of reasons. Most apparent are that you cannot rely on an integer write being atomic, nor can you assume that the code reading the value won't be optimized away when the compiler notices that the value cannot change in the current thread between checks. The C++ standard library does now provide atomic operations, though, as of C++11.

Anyway, what's wrong with condition variables here?

Computer viking
May 30, 2011
Now with less breakage.

That Turkey Story posted:

This is not true and could fail for any number of reasons. Most apparent are that you cannot rely on an integer write being atomic, nor can you assume that the code reading the value won't be optimized away when the compiler notices that the value cannot change in the current thread between checks. The C++ standard library does now provide atomic operations, though, as of C++11.

Anyway, what's wrong with condition variables here?

It should, to the best of my knowledge, be true for 8bit ints (and aligned wider ints on x86/amd64) - and isn't this exactly the use case the volatile keyword was invented for?

That said, yeah - use something less ugly.

That Turkey Story
Mar 30, 2003

Computer viking posted:

It should, to the best of my knowledge, be true for 8bit ints (and aligned wider ints on x86/amd64) - and isn't this exactly the use case the volatile keyword was invented for?

On certain architectures such writes may be atomic, but that's not standard. Also, even if the write itself is atomic, that doesn't mean you'll get the proper expected behavior. First, even if it's atomic, as I pointed out, if your compiler notices this thread isn't altering the value but keeps checking it, it very well may just optimize out the check entirely and loop forever. Apart from that, your compiler can optimize and re-order around the reads and writes to that variable, so that stuff which happens after the loop ends up happening before and vice versa, so if you are waiting until the condition is done before you do some kind of operation, that operation may very well happen before the loop even starts since as far as the compiler can tell, such a reordering has no visible effect but may be more efficient. Finally, even if a write is atomic and the compiler doesn't happen to reorder around it, you're still not in the clear since visibility between reads and writes may not be consistent between threads, particularly on multi-core systems. One possibility is that since operations are generally cached and don't happen directly to and from main memory, if the cores aren't using a shared cache and one has the thread doing the write and the other has the thread doing the read, even though the reads and writes may "happen", the two different threads will still have their own view of what the value is at that location. You need memory barriers associated with your operations. All of this is why if you want atomic operations, you cannot rely on assumptions. You need to be explicit, which nowadays means using the standard library's atomic operation functions, and even when you do that, you'd better be certain you understand the issues well enough to use it properly. Working with multiple threads with atomic operations is not a trivial thing, especially if your goal is lock-free programming.

And no, the volatile keyword was not for threading.

Computer viking
May 30, 2011
Now with less breakage.

Volatile is, however, for "this piece of memory might be changed or read by something the compiler can't know about, so never optimize out reads or writes to it" - which seems like it would apply here?

I know it won't prevent getting an "old" value; it says nothing about barriers or syncing. That might be acceptable, though - if it eventually sees the updated value. Which it might not - is there any guarantee that data written to memory in one thread will eventually show up for another thread on another CPU?

(And yes, I'm quite explicitly requiring threads to either read or write, and never both.)

Computer viking fucked around with this message at 16:35 on Jun 27, 2012

That Turkey Story
Mar 30, 2003

Computer viking posted:

Volatile is, however, for "this piece of memory might be changed or read by something the compiler can't know about, so never optimize out reads or writes to it" - which seems like it would apply here?
Nope, not with threading, unless that's changed in C++11 -- I think something was proposed to give volatile better meaning with respect to threads in C++11, but it was shot down, though I could be mistaken.

Computer viking posted:

I know it won't prevent getting an "old" value; it says nothing about barriers or syncing. That might be acceptable, though - if it eventually sees the updated value. Which it might not - is there any guarantee that data written to memory in one thread will eventually show up for another thread on another CPU?

No. Basically when it comes to threading, everything that low-level is left undefined unless you are using the standard library's locks or atomic operations.

Rottbott
Jul 27, 2006
DMC
As I understand it, volatile can prevent compiler re-ordering, but it can't do anything about hardware re-ordering. In practice it's enough on x86, but not on x64.

I'm dying to use the new C++11 atomic stuff but it doesn't seem to be supported by many compilers yet.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

Rottbott posted:

As I understand it, volatile can prevent compiler re-ordering, but it can't do anything about hardware re-ordering. In practice it's enough on x86, but not on x64.

That's pretty much it. Volatile is for memory-mapped IO, if you're using it for anything else chances are you're not doing it quite right.

Computer viking
May 30, 2011
Now with less breakage.

Right, I've been reading the C99 standard - assuming that volatile acts more or less the same there as in modern C++, the most important issue is that it does not even guarantee against software reordering. It does guarantee that writes will happen even if they seem pointless, and it does (as I understood it) guarantee that seemingly pointless repeat reads will remain in the code - if the result of the read will be used for something later. (That is - {while(!vol) stuff_that_never_touches_vol();} will stay, but {b=vol; b=1;} will be removed.) It does not, however, guarantee that a write will happen at the exact place it looks like in the code.
Consider something like { doHeavyStuff(); flag=1;}, where flag is volatile. It would be perfectly legal to set the flag first - some compilers on some archs take volatile a a hint that you want to keep the ordering as well, but that's not in the standard.

I can still construct ways in which it's useful, but eh - if you've got mutexes or semaphores or C++11 atomics or C11 atomic_flag (or inline asm), I'll cede that the posters above are right, and those are much better choices.

Computer viking fucked around with this message at 12:58 on Jun 28, 2012

That Turkey Story
Mar 30, 2003

Computer viking posted:

I can still construct ways in which it's useful
...No, not with respect to threads. It's undefined and that's it. You can try to say "well, technically it's undefined, but realistically such-and-such will probably happen" but you will be incorrect, both in terms of being a language lawyer and likely even in practice. This is what a lot of people either don't get or refuse to accept regarding threading and is the source of an endless amount of bugs. Just forget about it, undefined is undefined.

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!
On the subject of threading, is it the case that after a mutex or event or whatever you use for synchronization call, all data will be properly identical between the processors, or is there something you're supposed to do to mark the data as especially needing cross-thread safety, or some call to 'flush' the synchronization?

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Computer viking posted:

Right, I've been reading the C99 standard - assuming that volatile acts more or less the same there as in modern C++, the most important issue is that it does not even guarantee against software reordering. It does guarantee that writes will happen even if they seem pointless, and it does (as I understood it) guarantee that seemingly pointless repeat reads will remain in the code - if the result of the read will be used for something later. (That is - {while(!vol) stuff_that_never_touches_vol();} will stay, but {b=vol; b=1;} will be removed.)

This is not true. volatile does guarantee that loads and stores will be strictly performed as written; in particular, the compiler is not allowed to remove dead loads and stores. This is critical for memory-mapped I/O. I can lawyer this for you if you insist.

Note that certain expressions that are loads in C are not loads in C++03; however, many of those are loads again in C++11, although sometimes with slightly different behavior.

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

roomforthetuna posted:

On the subject of threading, is it the case that after a mutex or event or whatever you use for synchronization call, all data will be properly identical between the processors, or is there something you're supposed to do to mark the data as especially needing cross-thread safety, or some call to 'flush' the synchronization?

Synchronization is pretty much always formalized under a "happens before" rule, where if one thing "happens before" another then the second is guaranteed to see the effects of the first.

Applying that to mutexes, operations you do before releasing a mutex are guaranteed to "happen before" the release, and operations you do after acquiring a mutex are guaranteed to "happen after" the acquisition, and a release is guaranteed to "happen before" a subsequent acquisition.

In other words, everything you do before unlocking a mutex will be visible to everything you do after locking the same mutex later, so no, you don't need to do anything else to flush the synchronization.

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!
Cool, thanks. I'd been operating under that assumption, but all this talk of it being complicated made me start to doubt myself!

Computer viking
May 30, 2011
Now with less breakage.

rjmccall posted:

This is not true. volatile does guarantee that loads and stores will be strictly performed as written; in particular, the compiler is not allowed to remove dead loads and stores. This is critical for memory-mapped I/O. I can lawyer this for you if you insist.

Could you? I believe you, but I (apparently) have some issues parsing the relevant part of the standard. I looked at a c99 draft, but whatever you're more familiar with - if you have the time. :)

xgalaxy
Jan 27, 2004
i write code
Volatile only guarantees that reads/writes are in the order specified for each / between each volatile.
It makes no guarantees about the order of non-volatile reads/writes relative to a volatile.

So it is insufficient to protect a resource.

xgalaxy fucked around with this message at 18:50 on Jun 29, 2012

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe

Computer viking posted:

Could you? I believe you, but I (apparently) have some issues parsing the relevant part of the standard. I looked at a c99 draft, but whatever you're more familiar with - if you have the time. :)

It's actually pretty straightforward. In C++, we have these lovely little clauses:

"C++11 [intro.execution posted:

p1"]
The semantic descriptions in this International Standard define a parameterized nondeterministic abstract machine. This International Standard places no requirement on the structure of conforming implementations. In particular, they need not copy or emulate the structure of the abstract machine. Rather, conforming implementations are required to emulate (only) the observable behavior of the abstract machine as explained below.

This is the "as-if" rule, which says that abstract semantics only matter up to the point that they affect observable behavior.

"C++11 [intro.execution posted:

p8"]
Access [sic] to volatile objects are evaluated strictly according to the rules of the abstract machine.

This overrides that (under standard rules of construction, i.e. more specific statements override more general ones), saying that when we have an actual volatile object, every access to it is performed exactly according to the abstract semantics.

So if you have an assignment into a volatile l-value, we need to evaluate that strictly, i.e. that object needs to actually be in memory and you need to perform an actual store into that address.

For example, clang will happily treat *((char*) 0) = 0; as undefined behavior and optimize based on an assumption that that statement must not be reachable in the actual program, but if you instead cast to volatile char*, we just shut up and emit that store into that null pointer, yessir. (This is arguably not required, but it turns out that people writing kernels really want a way to be able to store to that address, and this was an acceptable compromise.)

raminasi
Jan 25, 2005

a last drink with no ice
Does anyone have Google Test experience? I've got a case that's crashing and bringing the whole test program down with it rather than just adding a test failure and I don't know how to make it stop (I don't even know what's causing the crash).

e: the problem appears to be triggered by function calls that appear after the crash :wth: This is optimization, right?

raminasi fucked around with this message at 22:24 on Jun 29, 2012

Jabor
Jul 16, 2010

#1 Loser at SpaceChem

xgalaxy posted:

Volatile only guarantees that reads/writes are in the order specified for each / between each volatile.
It makes no guarantees about the order of non-volatile reads/writes relative to a volatile.

It actually doesn't even make this guarantee, if you're just using it to access regular memory. It ensures that the compiler emits all the loads/stores in the right order, yes, but it does not emit any memory fences, or do anything else in order to ensure that the processor itself doesn't mess around with the order of accesses.

That Turkey Story
Mar 30, 2003

Jabor posted:

It actually doesn't even make this guarantee, if you're just using it to access regular memory. It ensures that the compiler emits all the loads/stores in the right order, yes, but it does not emit any memory fences, or do anything else in order to ensure that the processor itself doesn't mess around with the order of accesses.

Right. There are compilers out there that do define them with respect to threads, but unless C++11 changed it, I'm pretty positive it's not guaranteed. I know that since vc++ 7.1 or maybe 8 or so, volatile made loads from 32-bit integers have load-acquire semantics and stores have store-release semantics. Anyway, the point is, when doing threading in portable code, use the atomic operations in the standard library, if you want to use explicit atomic operations at all.

IratelyBlank
Dec 2, 2004
The only easy day was yesterday
I have a question about a bit array problem I am trying to work through. I am storing the bit array in a dynamic unsigned char, and I have mostly got the problem solved but when I set the bit of an index to either 1 or 0, it sets the same bit for every byte in that index position. For example let's say we start with 3 bytes: 00000000 00000000 00000000 and I want to switch position 1 to a 1. When I run my code, it will give me this result: 10000000 10000000 10000000, it will flip the first index of each byte. I am only addressing the char index of the first byte (0), so I'm totally lost as to why it would perform the same action on every byte. This is my code:

code:
void BitArray::Set   (unsigned int index)         // set bit with given index to 1
{
	unsigned int realIndex;
	
	if (index % (8 * sizeof(unsigned char)) == 0)
	{
		index -= 1;
		realIndex = 8;
	}
	else if (index > 8)
		realIndex = index % 8;
	else
		realIndex = index;

	const unsigned int SHIFT = 8 * sizeof(unsigned char);
	const unsigned MASK = 1 << SHIFT - realIndex;
	
	barray[index / (sizeof(unsigned char) * 8 )] |= MASK;
}
and barray is: barray = new unsigned char[size]; I'm stepping through an inspecting the value of barray[index / (sizeof(unsigned char) * 8 )], which does equate to barray[0], so I'm not sure why it is applying the same mask to 0, 1, and 2 unless there is something about masking that I don't understand. Perhaps I need a 3 byte mask or else it applies the same 1 byte mask across all bytes? I don't know.

Paniolo
Oct 9, 2007

Heads will roll.

GrumpyDoctor posted:

Does anyone have Google Test experience? I've got a case that's crashing and bringing the whole test program down with it rather than just adding a test failure and I don't know how to make it stop (I don't even know what's causing the crash).

e: the problem appears to be triggered by function calls that appear after the crash :wth: This is optimization, right?

Debug or release build?

That Turkey Story
Mar 30, 2003

IratelyBlank posted:

I have a question about a bit array problem I am trying to work through. I am storing the bit array in a dynamic unsigned char, and I have mostly got the problem solved but when I set the bit of an index to either 1 or 0, it sets the same bit for every byte in that index position. For example let's say we start with 3 bytes: 00000000 00000000 00000000 and I want to switch position 1 to a 1. When I run my code, it will give me this result: 10000000 10000000 10000000, it will flip the first index of each byte. I am only addressing the char index of the first byte (0), so I'm totally lost as to why it would perform the same action on every byte. This is my code:

code:
void BitArray::Set   (unsigned int index)         // set bit with given index to 1
{
	unsigned int realIndex;
	
	if (index % (8 * sizeof(unsigned char)) == 0)
	{
		index -= 1;
		realIndex = 8;
	}
	else if (index > 8)
		realIndex = index % 8;
	else
		realIndex = index;

	const unsigned int SHIFT = 8 * sizeof(unsigned char);
	const unsigned MASK = 1 << SHIFT - realIndex;
	
	barray[index / (sizeof(unsigned char) * 8 )] |= MASK;
}
and barray is: barray = new unsigned char[size]; I'm stepping through an inspecting the value of barray[index / (sizeof(unsigned char) * 8 )], which does equate to barray[0], so I'm not sure why it is applying the same mask to 0, 1, and 2 unless there is something about masking that I don't understand. Perhaps I need a 3 byte mask or else it applies the same 1 byte mask across all bytes? I don't know.

This code is over-complicated. Before trying to decipher what's going on exactly, there are a few things. First, what is the purpose of this in your current code:

code:
if (index % (8 * sizeof(unsigned char)) == 0)
{
  index -= 1;
  realIndex = 8;
}
else if (index > 8)
  realIndex = index % 8;
else
  realIndex = index;
All you want to do is take an index and convert it to a byte's index and a bit's index. This is just division and modulus and nothing else.

code:
unsigned const byte_index = index / 8,
               bit_index  = index % 8;
That's all. Also, to be really standard, use the constant CHAR_BIT instead of the number 8, since the number of bits in a char isn't necessarily 8. Also, you do sizeof(unsigned char) a lot -- this, on the other hand, is not necessary, since the standard defines sizeof(unsigned char) to always be 1.

Anyway, now that you have the byte_index and the bit_index, you can just do:
barray[byte_index] |= 1 << bit_index;

(untested)

Also, if you want to avoid reinventing the wheel, the standard has std::bitset and std::vector<bool>, both of which are implementations of bit-arrays (though the latter is sort of an embarrassment). Boost has boost::dynamic_bitset as well.

xgalaxy
Jan 27, 2004
i write code

That Turkey Story posted:

This code is over-complicated. Before trying to decipher what's going on exactly, there are a few things. First, what is the purpose of this in your current code:

code:
if (index % (8 * sizeof(unsigned char)) == 0)
{
  index -= 1;
  realIndex = 8;
}
else if (index > 8)
  realIndex = index % 8;
else
  realIndex = index;
All you want to do is take an index and convert it to a byte's index and a bit's index. This is just division and modulus and nothing else.

code:
unsigned const byte_index = index / 8,
               bit_index  = index % 8;
That's all. Also, to be really standard, use the constant CHAR_BIT instead of the number 8, since the number of bits in a char isn't necessarily 8. Also, you do sizeof(unsigned char) a lot -- this, on the other hand, is not necessary, since the standard defines sizeof(unsigned char) to always be 1.

Anyway, now that you have the byte_index and the bit_index, you can just do:
barray[byte_index] |= 1 << bit_index;

(untested)

Also, if you want to avoid reinventing the wheel, the standard has std::bitset and std::vector<bool>, both of which are implementations of bit-arrays (though the latter is sort of an embarrassment). Boost has boost::dynamic_bitset as well.

Personal preference but I prefer the explicit sizeof(char). If nothing else it at least self documents.

raminasi
Jan 25, 2005

a last drink with no ice

Paniolo posted:

Debug or release build?

Release. One of the libraries I'm using won't compile in Debug mode (I don't even know what flags are causing the problems - the library is that arcane.)

I've realized that a more likely problem is that something earlier is putting my program in an undefined state (probably a free to a garbage address), so that's what I'm tackling first, but if anyone has any brilliant suggestions I'm all ears.

OddObserver
Apr 3, 2009
If you are on an OS that supports it, valgrind. In that case, of course, you should be able to tweak build flags beyond Debug/release to get debug info in there.

Also, --gtest-filter will let you run a subset of tests

IratelyBlank
Dec 2, 2004
The only easy day was yesterday

That Turkey Story posted:

This code is over-complicated. Before trying to decipher what's going on exactly, there are a few things. First, what is the purpose of this in your current code:

code:
if (index % (8 * sizeof(unsigned char)) == 0)
{
  index -= 1;
  realIndex = 8;
}
else if (index > 8)
  realIndex = index % 8;
else
  realIndex = index;
All you want to do is take an index and convert it to a byte's index and a bit's index. This is just division and modulus and nothing else.

code:
unsigned const byte_index = index / 8,
               bit_index  = index % 8;
That's all. Also, to be really standard, use the constant CHAR_BIT instead of the number 8, since the number of bits in a char isn't necessarily 8. Also, you do sizeof(unsigned char) a lot -- this, on the other hand, is not necessary, since the standard defines sizeof(unsigned char) to always be 1.

Anyway, now that you have the byte_index and the bit_index, you can just do:
barray[byte_index] |= 1 << bit_index;

(untested)

Also, if you want to avoid reinventing the wheel, the standard has std::bitset and std::vector<bool>, both of which are implementations of bit-arrays (though the latter is sort of an embarrassment). Boost has boost::dynamic_bitset as well.

Thanks for the help, I got the same result using your code as my code so I inspected the way I was outputting the bytes and sure enough that was where my problem was. I fixed that and the problem went away completely.

Boz0r
Sep 7, 2006
The Rocketship in action.
What's the output when you negate an integer with an exclamation mark? like:

code:
!aninteger

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!

Boz0r posted:

What's the output when you negate an integer with an exclamation mark? like:

code:
!aninteger

code:
#include <stdio.h>

int main() {
 int x=0;
 printf("Negation of zero = %d\n",!x);
 x=382;
 printf("Negation of positive integer = %d\n",!x);
}

Output:
Negation of zero = 1
Negation of positive integer = 0

Boz0r
Sep 7, 2006
The Rocketship in action.
Nifty.

I'm learning to use the fork() command and such. I have a following if-statement that tests if the pid is 0 and runs a bit of code. When I make a breakpoint in that bit of code with gdb the breakpoint is never triggered. What am I doing wrong?

Adbot
ADBOT LOVES YOU

Hughlander
May 11, 2005

Boz0r posted:

What's the output when you negate an integer with an exclamation mark? like:

code:
!aninteger

To expand on what roomforthetuna posted, at a previous job we actually used the construct:
!!aninteger to be a branchless/warningless form of:
bool bImABool = (anintenger) ? true : false;

God I hated reading code like that.

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