28 Dec, 2008, Lobotomy wrote in the 1st comment:
Votes: 0
(the following topic primarily concerns the C programming language, optionally in addition to the C99 mode with GNU extensions which I currently use)

I'm having some difficulty deciding on the sort of method to use for storing the results of string utility functions for returning to their callers, so I'd like to solicit some input on the matter. What I'm speaking of are functions used to perform some operation on an input string, then put the result into an allocated buffer of some sort and return it.

For instance, suppose you have a function "capitalize" which takes a string, capitalizes the first character, puts the result into a buffer and then returns a pointer to the buffer. The problem lies in what sort of storage to use for the buffer. Traditionally, the way I've seen it done is to use a static char buffer of a defined size within the function. The problem I have with that method is that I'm looking to have my string infrastructure become mostly/fully limitless; where in terms of string utility functions means that they need to handle strings of any size. The other shortcoming of that method is that you also can't perform repeat calls of that function within a single function call elsewhere; doing so causes the output to get screwy. I.e, if you tried to do "example_printf( thing, "%s %s", capitalize( ex1 ), capitalize( ex2 ) );" it would break. To fix the problem you're forced to break the format into multiple lines, calling the function in question only once per call.

What I'm looking for is a good, hopefully quick, method of getting both things I'm looking for accomplished. I.e, the function can store strings of any size, and can be called in succession without corrupting the output. There are a number of ways I've thought of for handling this, with varying results (potential or otherwise).

One method I've thought of, which is currently set in the code awaiting a better replacement, is to use a static pointer to an allocated buffer that is expanded as needed, with the input placed into the buffer and the pointer returned. This fulfills the requirement of being able to handle strings of any size, but not of allowing the function to be called in direct succession. As a side note, for efficiency sake the buffers are allocated to a somewhat large default size in an effort to cut down on the number of times they would need to be expanded. In theory, most uses of the function would be under the limit so it would not need to be expanded very often, but when the need arises for such the function would be able to handle it.

A second method I've thought of, which I'm only just thinking about for the time being, would be to create a system of disposable strings which are allocated every time the function in question is called, and then disposed of at some later point; likely at the end of the main game loop to try and ensure that the functions are out of scope and nothing will break from freeing the strings. This would likely solve both problems, but the thing that gives me pause in implementing such a system is the potential overhead that could be incurred from having allocations performed so many times (assuming conditions where the functions are being called often).

One of the impressions I've gotten so far from the use of static buffers within string utility functions is that it is designed to cut down on allocations and thus speed things up considerably. What I'm trying to decide is whether or not that desire is particularly relevant these days considering the speed and capabilities of today's computers. I've brought up similar points a number of times, and I can't help but wonder if this is another instance of where the benefit to the form and function of the code outweighs the potential additional CPU/RAM usage. If it is, I find that I'm leaning towards the idea of using something along the lines of the second method described.

Anyhow, some ideas, advice, etc on the matter would be appreciated. :thinking:
28 Dec, 2008, Davion wrote in the 2nd comment:
Votes: 0
I'm pretty sure I get what you're saying, and there is one method in particular I'm rather quite fond of. It's a similar way to the way one_argument does it. Pass an allocated buffer off to the function to be set in the parameters. An example of capitalize.

char * capitalize(char *dest, const char *src)
{ int i;
for( i = 0 ; src[i] != '\0' ; ++i )
dest[i] = LOWER(src[i]);
dest[i] = '\0';
dest[0] = UPPER(dest[0]);
return dest;
}


Then to use this code, it'd be something like

char *name[MSL];
capitalize(name, ch->name); //name will now be capitalized.


If you'd want to do something with it in a sprintf call for instance,

sprintf("%s", capitalize(tmp, ch->name) )


You'll just be required to pass off a valid buffer each time you make the call. If you want to use it more than once in the same sprintf, make sure you use separate buffers.
28 Dec, 2008, David Haley wrote in the 3rd comment:
Votes: 0
I'm willing to bet that static buffers are used not to save on allocations etc., but to guard against having to free memory. Is it really a benefit to the form and function of the code to have to free memory after every single call to the functions? The main problem with static buffers is the concurrency one; you can only store the result one string at a time.

Davion's solution is quite good; instead of having to free memory, you can declare a buffer on the stack as is done elsewhere in the code. It's probably one of the best approaches to this fairly messy problem.

What you're running into is, frankly, what should be a very convincing argument to use C++ if only for the std::string object…
28 Dec, 2008, quixadhal wrote in the 4th comment:
Votes: 0
A third option you might consider, if you're not opposed to third party libraries, is to use a garbage collection system such as gcmalloc. If you used gcmalloc to allocate all your strings, you wouldn't have to (force the caller to) remember to deallocate them later.

It's not as efficient as properly using malloc/free, but as you say, hardware today is typically far in excess of what a typical MUD needs unless it makes heavy use of pathfinding (via A*) or some actual AI routines.
28 Dec, 2008, elanthis wrote in the 5th comment:
Votes: 0
quixadhal said:
It's not as efficient as properly using malloc/free


You might be surprised. A good garbage collector can vastly increase performance over manual memory management, especially on modern hardware. Conservative collectors used for C/C++ apps are pretty limited in the techniques they can use, but even the extremely-conservative Boehm-Demers-Weiser collector can match and in some cases exceed the memory management performance of traditional malloc()/free() for many applications. free() isn't free, you know. :) A good garbage collection reduces the amount of work the system has to perform to manage memory and improves performance in other ways by using more advanced memory allocation techniques; they are especially efficient when it comes to allocating many small, temporary memory objects, which is exactly the kind of thing the OP is asking about.

That said, retro-fitting a garbage collection system onto a large existing codebase is a nightmare. I've done it before, so believe me on that one. It doesn't help the neither C nor C++ provides the necessary features to implement truly automatic garbage collection (that is, you have to modify a lot of code to make it work correctly and efficiently, and you have to write extra code when allocating memory to inform the garbage collector about the properties of the allocation). The absolute smartest thing the OP can do is just start using C++ and use its automatic memory management features built-in to the implementations of std::string, std::vector, etc. Mix that up with a bit of Boost (especially shared_ptr) and the pains and dangers of manual memory management can all but be forgotten.

At some point C++ may be much easier to use with garbage collection. C++0x is getting some of the language primitives needed to make it really useful, but it's up to the compilers to start implementing it properly. It likely won't be until the next release of C++ (probably released around 2019, and not to be fully implemented in real compilers until the mid 2020's) has all the language and library features to make GC fully painless and invisible. Until then, though, GC and C/C++ are only a good fit if you're going to design an application and its supporting libraries from scratch with GC in mind.
28 Dec, 2008, Lobotomy wrote in the 6th comment:
Votes: 0
Davion said:
I'm pretty sure I get what you're saying, and there is one method in particular I'm rather quite fond of. It's a similar way to the way one_argument does it. Pass an allocated buffer off to the function to be set in the parameters.

That's certainly a good option insofar as solving the multiple calls problem is concerned. There are only two problems with it though. Mainly, the restricted buffer size. In that example the buffer itself has to be set to a defined size before being sent to the function. In cases where the function creates output that is larger than the buffer, things would break. It'd be nice if it were somehow possible to use C99's variable arrays to get around that, but even with them the size of the resulting output would have to be known before entering the function.

The other problem is something I neglected to mention: I'm trying to keep the functions in question as self contained as possible. Where functions like this are concerned, that means removing the need to define a buffer for the function to use on each call. Using the example, that means that to use the capitalize function all I would then need to do is merely call the function itself. So, while the solution is decent, it's not something I'll be wanting to use. Thanks, though.

quixadhal said:
A third option you might consider, if you're not opposed to third party libraries, is to use a garbage collection system such as gcmalloc. If you used gcmalloc to allocate all your strings, you wouldn't have to (force the caller to) remember to deallocate them later.


I'm not at all opposed to using third party libraries/code, so long as they don't create more problems than they solve. I know I've heard of gcmalloc before at some point, but I'd forgotten about it again until you brought it up just now. I'm tempted to make use of just such a thing, if for nothing else the added ease of programming that could be gained by not having to worry about manually freeing memory; that is what happens with something like gcmalloc, correct? I.e, I only need to allocate something, and then when I want it to be freed the pointers referencing it merely need to be nulled; after which point the garbage collector takes care of the rest? I also wonder how quickly the collector takes to cleaning away allocated data; whether it's gone within micro-seconds/seconds, or if it possibly sits there for even longer.

elanthis said:
You might be surprised. A good garbage collector can vastly increase performance over manual memory management, especially on modern hardware. Conservative collectors used for C/C++ apps are pretty limited in the techniques they can use, but even the extremely-conservative Boehm-Demers-Weiser collector can match and in some cases exceed the memory management performance of traditional malloc()/free() for many applications. free() isn't free, you know. :) A good garbage collection reduces the amount of work the system has to perform to manage memory and improves performance in other ways by using more advanced memory allocation techniques; they are especially efficient when it comes to allocating many small, temporary memory objects, which is exactly the kind of thing the OP is asking about.

Thinking about the use of third party garbage collectors does bring a particular thought to mind. How compatible are they with debugging tools such as gdb and valgrind? I'd half imagine garbage collectors to remove the need to use at least valgrind, but I also suspect that is not necessarily the case - at least with regards to things such as arrays and bounds checking, among others. It's not that I'd particularly want to stop using such debuggers, but if it they become unnecessary I'd chalk that up as a benefit.

elanthis said:
That said, retro-fitting a garbage collection system onto a large existing codebase is a nightmare.

I'd imagine so. Luckily for me (and I suppose I neglected to mention this as well, my bad) the codebase I'm working on is still very small. It's a custom one I've been tinkering with for some time, originally based off of SocketMUD. I've been continually re-writing the entire codebase itself time and again as I find or come up with better ways of doing things, so the task of restructuring the codebase isn't going to be much of a problem for me in this particular instance.

elanthis said:
The absolute smartest thing the OP can do is just start using C++ and use its automatic memory management features built-in to the implementations of std::string, std::vector, etc.

Well, to be specific the absolute smartest thing I could do would likely be to jump to some other language at a higher level than C++; such as Python or Ruby and the like. Although, as I still can't seem to grok those languages for some reason I'm stuck with C/C++. To that end, I have thought of using C++ quite a bit. However, as I've mentioned briefly in the past I'd rather wait until C++0x is completed before trying to make that particular transition.

With regards to C++0x though, are you absolutely sure on the 2019/2020's timeframe you've stated? I ask as I'd always heard up until now that the release timeframe is actually 2009. I've read that some of the C++0x features are accessible even now, although it's not recommended due to being incomplete and experimental.
28 Dec, 2008, David Haley wrote in the 7th comment:
Votes: 0
Lobotomy said:
The other problem is something I neglected to mention: I'm trying to keep the functions in question as self contained as possible. Where functions like this are concerned, that means removing the need to define a buffer for the function to use on each call.

It kind of sounds like you want to have your cake and eat it too. Almost no matter how you look at it, in C, without using something like the garbage collection libraries, you're stuck with: (a) providing a buffer to the function, (b) using a static buffer, or © allocating strings in the function (which you would need to free after calling the function). You mentioned something about having a pool of strings, but then you create a host of new problems. When do you free them? How many do you have? How do you recycle them? What if you run out? etc.

Lobotomy said:
To that end, I have thought of using C++ quite a bit. However, as I've mentioned briefly in the past I'd rather wait until C++0x is completed before trying to make that particular transition.

It costs you almost nothing to start using std::string now. If you want to wait around until the new extensions become completely standardized, you might have to wait a loooooong time. The 2009 date you know of is merely the date at which the standard will be introduced – then you need to wait for all of this to be supported by compilers and so forth in some standard manner.

What are your reasons for waiting for the new standard to be approved before using any C++ features? It seems to me like you're hurting yourself substantially in the meantime. This entire problem simply disappears when you have objects like std::string. If you really want to use as little C++ as possible until the new standard is eventually finished, that's fine: you don't have to use much at all. If you used std::string, pretty much the only thing you'd have to make sure you did would be to manage memory with new/delete instead of malloc/free.
29 Dec, 2008, Tyche wrote in the 8th comment:
Votes: 0
elanthis said:
free() isn't free, you know. :)


Speaking of free()…
$ cat memtest.c 
#include <stdio.h>
#include <malloc.h>
#define HUNK 1024*1024*1024
main(){
void* ptr;
printf("No memory allocated yet. Check procps now.\n");
printf("Hit any key to continue\n");
getchar();
ptr = malloc(HUNK);
printf("%d memory allocated. Check procps now.\n",HUNK);
printf("Hit any key to continue\n");
getchar();
free(ptr);
printf("All memory freed. Check procps now.\n");
printf("Hit any key to continue\n");
getchar();
}


$ gcc memtest.c; ./a
No memory allocated yet. Check procps now.
Hit any key to continue

$ procps -FCa
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
jlambert 5356 1976 0 524 2048 0 23:43 tty0 00:00:00 ./a

1073741824 memory allocated. Check procps now.
Hit any key to continue

$ procps -FCa
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
jlambert 5356 1976 0 263197 4204 0 23:43 tty0 00:00:00 ./a

All memory freed. Check procps now.
Hit any key to continue

$ procps -FCa
UID PID PPID C SZ RSS PSR STIME TTY TIME CMD
jlambert 5356 1976 0 263197 4200 0 23:43 tty0 00:00:00 ./a
29 Dec, 2008, quixadhal wrote in the 9th comment:
Votes: 0
YAY! A chance to use another of my useless UNIX trivia bits! :)

If you want to know WHY free() doesn't actually seem to return the memory you just sucked up, check out the man page for sbrk()!

When you use malloc/calloc/realloc, it will look for available memory segments in the segment list of your program's data segment. If there are none of sufficient size, it calls sbrk() to extend the data segment by some power of 2 amount. When you free() a block, it gets added to the free list, but no corresponding retraction of the data segment happens.

Eventually, data pages with no active pointers are swapped out to disk (if virtual memory is enabled), but they aren't released to the system memory pool until the process terminates.

So, NOT freeing the mallocs will cause you to keep extending the data segment and growing larger and larger, freeing them won't let you shrink down again, but it does let you reuse what you already have.
29 Dec, 2008, Tyche wrote in the 10th comment:
Votes: 0
Well I came up with four methods, three of which are common in the standard C library…

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// method 1
// return pointer to static string
//
// non-reentrant, fixed length limits, no housekeeping
char * capitalize_1(char const* src) {
static char dst[32768];
int i = 0;

0[dst] = '\0';
while (i[src]) {
if (i == 0)
i[dst] = toupper(i[src]);
else
i[dst] = i[src];
i++;
}
i[dst] = '\0';
return dst;
}

// method 2
// modify string in place
//
// reentrant, caller must preserve string if desired
char * capitalize_2(char * src) {
if (strlen(src) > 0)
*src = toupper(*src);
return src;
}

// method 3
// return new string
//
// reentrant, caller must free string
char * capitalize_3(char const* src) {
int i = 0;
size_t len = strlen(src);
char * dst = (char *) malloc(len + 1);

0[dst] = '\0';
while (i[src]) {
if (i == 0)
i[dst] = toupper(i[src]);
else
i[dst] = i[src];
i++;
}
i[dst] = '\0';
return dst;
}

// method 4
// copy string
//
// reentrant, caller must provide allocated string
char * capitalize_4(char * dst, char const* src) {
int i = 0;

0[dst] = '\0';
while (i[src]) {
if (i == 0)
i[dst] = toupper(i[src]);
else
i[dst] = i[src];
i++;
}
i[dst] = '\0';
return dst;
}

int main() {
char a[6] = "hello";
char b[6] = "hello";
char * sptr;

printf("1: %s %s\n",a, capitalize_1(a));

printf("2: %s ",a);
printf("%s\n", capitalize_2(a));

sptr = capitalize_3(b);
printf("3: %s %s\n",b, sptr);
free(sptr);

sptr = (char *) malloc(strlen(b) + 1);
printf("4: %s %s\n",b, capitalize_4(sptr, b));
free(sptr);

return 0;
}


While it really depends on the particular function I would say my own preferences lean toward method 3 or 4.
Seems the C standard library prefers method 4 over most others.
Any others?

EDIT: fixed some nasty off by one errors above
29 Dec, 2008, Tyche wrote in the 11th comment:
Votes: 0
quixadhal said:
YAY! A chance to use another of my useless UNIX trivia bits! :)

If you want to know WHY free() doesn't actually seem to return the memory you just sucked up, check out the man page for sbrk()!

When you use malloc/calloc/realloc, it will look for available memory segments in the segment list of your program's data segment. If there are none of sufficient size, it calls sbrk() to extend the data segment by some power of 2 amount. When you free() a block, it gets added to the free list, but no corresponding retraction of the data segment happens.

Eventually, data pages with no active pointers are swapped out to disk (if virtual memory is enabled), but they aren't released to the system memory pool until the process terminates.

So, NOT freeing the mallocs will cause you to keep extending the data segment and growing larger and larger, freeing them won't let you shrink down again, but it does let you reuse what you already have.


Knowing the above and working on the RaM project, I suppose one might be able contrive some actual tests IRT the much maligned but little understood Merc/ROM memory system. ;-)
29 Dec, 2008, Tyche wrote in the 12th comment:
Votes: 0
Okay so here's two more varieties:

#include <stdio.h>
#include <ctype.h>

// method 5
// safer than method 4
//
char * capitalize_5(char * dst, size_t dst_sz, const char * src, size_t src_sz) {
size_t i = 0;

while (i < src_sz && i < dst_sz) {
if (i == 0)
i[dst] = toupper(i[src]);
else
i[dst] = i[src];
i++;
}
dst[dst_sz-1] = '\0';
return dst;
}

// method 6
// safer than method 4 - uses iterator concept
//
char * capitalize_6(char * dst, char * dst_end, const char * src, const char * src_end) {
char * dptr = dst;
const char * sptr = src;

while (dptr < dst_end && sptr < src_end) {
if (sptr == src)
*dptr = toupper(*sptr);
else
*dptr = *sptr;
sptr++;
dptr++;
}
*(dst_end-1) = '\0';
return dst;
}

#define MSL 256
int main() {
char src[MSL] = "hello";
char dst[MSL];

printf("5: %s %s\n",src, capitalize_5(dst, MSL, src, MSL));
printf("6: %s %s\n",src, capitalize_6(dst, dst+MSL, src, src+MSL));
return 0;
}
29 Dec, 2008, elanthis wrote in the 13th comment:
Votes: 0
Lobotomy said:
Well, to be specific the absolute smartest thing I could do would likely be to jump to some other language at a higher level than C++; such as Python or Ruby and the like. Although, as I still can't seem to grok those languages for some reason I'm stuck with C/C++. To that end, I have thought of using C++ quite a bit. However, as I've mentioned briefly in the past I'd rather wait until C++0x is completed before trying to make that particular transition.


That is pretty pointless. C++ works just fine today. Sticking with C for no reason other than waiting for a new version of C++ is like saying that you're going to stick with driving a horse and buggy until they make flying cars. :p

C++0x adds a lot of nice stuff over current C++, sure, but C++ today offers even more nice stuff over C.

Quote
With regards to C++0x though, are you absolutely sure on the 2019/2020's timeframe you've stated? I ask as I'd always heard up until now that the release timeframe is actually 2009. I've read that some of the C++0x features are accessible even now, although it's not recommended due to being incomplete and experimental.


You're not going to see complete C++0x support in a real, stable compiler for years. C++0x includes the quite huge and complicated Concepts feature, which in turn is required to be fully working for other C++0x features to work (like the new-style for loop, among others).

G++ today has support for a very small number of C++0x features, not even including some of the easier-yet-most-interesting such as automatic type deduction. The concepts-gcc work seems all but stalled. It seems to take on average about 5 years for a new version of C++ to be (mostly) supported by all major compilers, and given what a huge addition concepts are, I would not be surprised if it takes a little longer thing time around. On the other hand, maybe C++ compiler developers are getting quicker at implementing new features due to modern compiler designs… I don't know. I think 5 years is a decent estimate on the time frame before you can start using most of C++0x without requiring an experimental compiler.

quixadhal said:
So, NOT freeing the mallocs will cause you to keep extending the data segment and growing larger and larger, freeing them won't let you shrink down again, but it does let you reuse what you already have.


Note that free() will sometimes actually free memory. :) Large block allocations through malloc() will on many UNIX implementations (including glibc as used on Linux) use mmap() to allocate an anonymous private block, and free() will in turn munmap() that block. That results in performance improvements as well assisting in avoiding fragmentation.
29 Dec, 2008, David Haley wrote in the 14th comment:
Votes: 0
elanthis said:
C++0x adds a lot of nice stuff over current C++, sure, but C++ today offers even more nice stuff over C.

I agree with this. The new C++0x features are pretty nice, but basically icing on the cake compared to the benefit C++ gives over C.
elanthis said:
You're not going to see complete C++0x support in a real, stable compiler for years. C++0x includes the quite huge and complicated Concepts feature, which in turn is required to be fully working for other C++0x features to work (like the new-style for loop, among others).

G++ today has support for a very small number of C++0x features, not even including some of the easier-yet-most-interesting such as automatic type deduction. The concepts-gcc work seems all but stalled. It seems to take on average about 5 years for a new version of C++ to be (mostly) supported by all major compilers, and given what a huge addition concepts are, I would not be surprised if it takes a little longer thing time around. On the other hand, maybe C++ compiler developers are getting quicker at implementing new features due to modern compiler designs… I don't know. I think 5 years is a decent estimate on the time frame before you can start using most of C++0x without requiring an experimental compiler.

If the time it took to get the STL standardized (heh, standardized standard template library…) across compilers, especially gcc and MSVC, is any indication, I would not be optimistic at all about how quickly this will happen.
EDIT: so, yes, I'm agreeing with elanthis again: it will take quite a while, even if the standard itself comes out in 2009. Big difference between a standards document and the implementation(s).
30 Dec, 2008, quixadhal wrote in the 15th comment:
Votes: 0
Don't forget that once the standard comes out, Microsoft will have to generate a competing not-quite-compatible standard for C++ .NET, so that the 90% of the world that develops under Windows will remain in the fold, and the rest of the universe will thus have to take even longer arguing about following the standard properly vs. cross-platform compatibility.

Oh, did I say that out loud? :devil:
30 Dec, 2008, elanthis wrote in the 16th comment:
Votes: 0
quixadhal said:
Don't forget that once the standard comes out, Microsoft will have to generate a competing not-quite-compatible standard for C++ .NET, so that the 90% of the world that develops under Windows will remain in the fold, and the rest of the universe will thus have to take even longer arguing about following the standard properly vs. cross-platform compatibility.

Oh, did I say that out loud? :devil:


You mean the same way that GCC is going to continue have a bazillion extensions while lacking other standardized features for about 10 years? :p

Microsoft's C++ support is pretty good these days, actually. They took a long time mostly because they added incompatible features before there even _was_ a standard, and at that point they had to either choose between breaking old apps (bad bad bad) or being compatible with compilers only used by 1% of their customers (who cares?). The latest versions have full C++98 support, if I recall correctly.

Compare to GCC which took a long time mostly because the GNU folks have a personal bias against anything other than C and LISP. :p

UPDATED ADDITIONAL COMMENT: looks like GCC is actually moving along faster than I had anticipated – they've even managed to land support for automatic type deduction in variable declarations (new auto keyword behavior) in 4.4.
30 Dec, 2008, David Haley wrote in the 17th comment:
Votes: 0
MS did a fairly poor job with template support, though… I remember that as you went from MSVC6 to 2003 to 2005 code would compile that didn't before, or not compile but did before. Last time I checked their template support was good.

But to be honest, I've never had trouble with g++… what kind of issues have you run into? Sure, they implement all kinds of extensions (which are kind of dangerous IMO because it makes the unaware think it's part of the language) but their standards support has usually been good, at least IME…
30 Dec, 2008, elanthis wrote in the 18th comment:
Votes: 0
DavidHaley said:
But to be honest, I've never had trouble with g++… what kind of issues have you run into?


The exact same issues you just mentioned with VC++. You can even check the release notes to see which incompatible changes were made in each GCC release; it's not like they're secret. C++ has had a HUGE stigma on Linux and other Free OSes for a very long time because of the constantly changing C++ support in GCC until a few years ago.

Pretty much every single 2.x and 3.x release of GCC totally broke just about every moderately complicated C++ program, and even the first few 4.x releases included breakage in a few less-used areas of the language. Hell, I had to make some small tweaks to C++ apps as recently as the release of GCC 4.2. I don't recall anything breaking with 4.3 (there were some new warnings enabled by -Wall that popped up, but no errors). 4.4 doesn't look like it's going to break anything either, thankfully.

I think that GNU (like Microsoft) has finally nailed down their C++ standard compliance so breakages are essentially a thing of a past, but they definitely used to happen a _lot_.
30 Dec, 2008, David Haley wrote in the 19th comment:
Votes: 0
I guess I didn't start using g++ seriously until 2004ish or so; before that I did most C++ development with MSVC++. So I didn't really notice these problems. I guess it's not too surprising that GNU had its own share of issues…
30 Dec, 2008, elanthis wrote in the 20th comment:
Votes: 0
Yeah, I've had the pleasure of being a Linux/GCC user for almost a decade now. Since 1999, I think, starting with Slackware 4.1 or something like that. Those were the days, man, those were the days… ;) I got turned on to Linux because I could easily understand how all the components worked, even with my vastly limited experience and knowledge back then. These days, there are so many over-engineered and bloated components in Linux that I almost have an easier time understanding how Vista works… :/

A Linux basic system requires at least five daemons: init or a variant, udev, hald, dbus, and ConsoleKit. Each of which uses an entirely different configuration format and file layout, for no good ****ing reason. And they're just adding more and more daemons, like NetworkManager, Pulseaudio, DeviceKit and so on. All in addition to the almost-optional oldies like cron, atd, syslod, ksyslogd, irqbalanced, acpid, gdm, X, and on and on and on. All put their configuration files in different places with different names with different syntaxes, so truly groking a modern Linux system requires you to understand a bazillion different components, their various methods of achieving identical functionality, and a several domain-specific configuration and scripting languages for each. Some are written in ANSI C + POSIX, some written over glib, some in C++, some using other random system abstraction libraries, some in Python, some using a lot of shell scripts; and the ones coded in the same language just use different naming, indentation, and capitalization techniques, so an app using glue libraries ends up using types named Type, Libtype, LIB_TYPE, type_t, TypeT, lib_Type_t, TTYPE, and gType. It's a total mess. And just to add insult to injury, apparently even writing a man page for a command is no longer in style, so all the commands and config files are totally undocumanted in any standard, easy-to-find format. ARGH!

… so yeah, I have a lot of experience with GCC and Linux development environment, but I'm finding myself using Windows a lot more often these days, and even using MSVC++ here and there, which I haven't done since I was a freshmen in college.
0.0/20