C++ Features Adapted as C Idioms

Julian Scott
Julian Scott

A lot of people on Holla Forums complain about C++ being too bloated and C being too lacking. Why not adapt C++ features as C programming practices?
For example: for constructor/destructor autocalls, void main(void) {
thing_t my_thing;
thing_construct(&my_thing);
// ...do things...
thing_destruct(&my_thing);
}
or the copy constructor, thing_t thing1, thing2;
thing_construct(&thing1);
thing_construct(&thing2);
// ...
thing_copy(&thing1, &thing2);
// move constructor
thing_move(&thing1, &thing2);
//...

void thing_move(thing_t *to, thing_t *from) {
free(to->data);
to->data = calloc(from->size, 1);
memcpy(to->data, from->data, from->size);
thing_destruct(from);
}

It's not pretty, but I believe it's systematically similar. What does user think?

All urls found in this thread:
https://github.com/crawl/crawl/blob/master/crawl-ref/source/ability.cc#L1796
https://dev.mysql.com/doc/refman/5.7/en/c-api-prepared-statements.html
https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
Henry Ortiz
Henry Ortiz

A lot of people on Holla Forums complain about C++ being too bloated and C being too lacking. Why not adapt C++ features as C programming practices?

Becuase if C programmers liked those features they wouldn't complain about them you idiot.

Landon Hughes
Landon Hughes

818056(Me)
Who am I quoting?

Nicholas Evans
Nicholas Evans

But that's what people already do in C and have been doing since before C++.

Mason Howard
Mason Howard

Why doing what you propose, instead of writing C-style code in C++ and using C++ features only when they are useful in the project, rather than spamming them everywhere?

Ryan Adams
Ryan Adams

It would still lack of garbage collection.

Anthony Foster
Anthony Foster

copy constructor in C
Nigger we avoid copying.

Ryder Hall
Ryder Hall

there is no reason not to use modern c++
its much better than c

John Butler
John Butler

It's worth not using modern C++ just to keep the modern C++ programmers out.

Luke Green
Luke Green

is parroting memes all you can do?

Leo Hill
Leo Hill

Because "bloat" is nothing but a meme.

Adrian White
Adrian White

It's true, though. And I'm a C++ programmer.

Easton Martin
Easton Martin

Strings in C are garbage.

Charles Ward
Charles Ward

You should read that book about doing oop with only ansi c

Henry Cook
Henry Cook

Y'all niggas gotta read the code to Dungeon Crawl Stone Soup. It's so fucking easy to follow that you'll realize you only ever need blame yourself when you end up with unreadable C

Joshua Brooks
Joshua Brooks

Stay bad.

Hudson Myers
Hudson Myers


struct arena_error : public runtime_error
{
explicit arena_error(const string &msg) : runtime_error(msg) {}
explicit arena_error(const char *msg) : runtime_error(msg) {}
};

C++ was a mistake.

Jackson Roberts
Jackson Roberts

OOP was a mistake.

Grayson Ramirez
Grayson Ramirez

This is some quality garbage, user. Thanks for the humor.

const char* card_name(card_type card)
{
switch (card)
{
case CARD_VELOCITY: return "Velocity";
case CARD_EXILE: return "Exile";
case CARD_ELIXIR: return "the Elixir";
case CARD_STAIRS: return "the Stairs";
case CARD_TOMB: return "the Tomb";
case CARD_WILD_MAGIC: return "Wild Magic";
case CARD_ELEMENTS: return "the Elements";
case CARD_SUMMON_DEMON: return "the Pentagram";
case CARD_SUMMON_WEAPON: return "the Dance";
case CARD_SUMMON_FLYING: return "Foxfire";
case CARD_RANGERS: return "the Rangers";
case CARD_SHAFT: return "the Shaft";
case CARD_VITRIOL: return "Vitriol";
case CARD_CLOUD: return "the Cloud";
case CARD_STORM: return "the Storm";
case CARD_PAIN: return "Pain";
case CARD_TORMENT: return "Torment";
case CARD_WRATH: return "Wrath";
case CARD_WRAITH: return "the Wraith";
case CARD_SWINE: return "the Swine";
case CARD_ORB: return "the Orb";
case CARD_ILLUSION: return "the Illusion";
case CARD_DEGEN: return "Degeneration";
case CARD_FAMINE: return "Famine";

#if TAG_MAJOR_VERSION == 34
// Removed cards.
case CARD_MERCENARY: return "the Mercenary";
case CARD_ALCHEMIST: return "the Alchemist";
case CARD_CURSE: return "the Curse";
case CARD_VENOM: return "Venom";
case CARD_FORTITUDE: return "Fortitude";
case CARD_HAMMER: return "the Hammer";
case CARD_XOM: return "Xom";
case CARD_FEAST: return "the Feast";
case CARD_WARPWRIGHT: return "Warpwright";
case CARD_SUMMON_UGLY: return "Repulsiveness";
case CARD_PLACID_MAGIC: return "Placid Magic";
case CARD_CRUSADE: return "the Crusade";
case CARD_HELM: return "the Helm";
case CARD_BLADE: return "the Blade";
case CARD_SHADOW: return "the Shadow";
case CARD_POTION: return "the Potion";
case CARD_FOCUS: return "Focus";
case CARD_HELIX: return "the Helix";
case CARD_DOWSING: return "Dowsing";
case CARD_BANSHEE: return "the Banshee";
case CARD_SOLITUDE: return "Solitude";
case CARD_PORTAL: return "the Portal";
case CARD_WARP: return "the Warp";
case CARD_BATTLELUST: return "Battlelust";
case CARD_METAMORPHOSIS: return "Metamorphosis";
case CARD_SHUFFLE: return "Shuffle";
case CARD_EXPERIENCE: return "Experience";
case CARD_SAGE: return "the Sage";
case CARD_TROWEL: return "the Trowel";
case CARD_MINEFIELD: return "the Minefield";
case CARD_GENIE: return "the Genie";
case CARD_GLASS: return "Vitrification";
case CARD_BARGAIN: return "the Bargain";
case CARD_SUMMON_ANIMAL: return "the Herd";
case CARD_SUMMON_SKELETON: return "the Bones";
case CARD_WATER: return "Water";
case CARD_SWAP: return "Swap";
#endif

case NUM_CARDS: return "a buggy card";
}
return "a very buggy card";
}

how do i array

Kayden Wilson
Kayden Wilson

Let me guess, translations are done with pre-processor macros as well?

Joshua Sanders
Joshua Sanders

I didn't think it could actually be that bad.
ability.cc
literally the first source file
3800 LOC
80 lines of #include
almost half of the file is made up of a single switch statement
https://github.com/crawl/crawl/blob/master/crawl-ref/source/ability.cc#L1796

Xavier Murphy
Xavier Murphy

What's wrong with a big switch statement?
How would you be doing it?

Alexander Richardson
Alexander Richardson

I am working on a dataabase driven app write now, and goddamn, the number of mallocs required is stupid. String concatention in C is retarded.

Alexander Collins
Alexander Collins

Its as I'd that's already best practice.

Gavin Anderson
Gavin Anderson

and how do you do that? can you be more specific?
in any nontrivial program there will be some copying somewhere.

Dominic Cooper
Dominic Cooper

When not written by a Pajeet, code like this would compartmentalize rather than just glue fucking everything into a giant switch statement. A good way to realize what's wrong and also think about the right way to do it would be to ask yourself, "how would I add support for mods here?". You'd have some sort of struct representing things like this that would have its callback registered with the ability code. The result would be an ability.cc that is very small, ability code that could be grouped into its own file, and ability.cc could use datastructures to do the lookups rather than potentially roll through hundreds of comparisons looking for a match.

Nicholas Lopez
Nicholas Lopez

Maybe it's just your inexperience? C isn't Java, we avoid allocations. Software that has to be fast doesn't even use malloc.

Adam Turner
Adam Turner

I'm not sure how I can describe it, but it's really rare that good C and C++ copy anything. For an example, I just grepped 100k LoC of my C++ code for them and there were only 3.
There's probably a difference here depending on what language you came from. If you went from C to C++, you're unlikely to do something like add a copy constructor so you can let stl containers value copy your data because you know how fucking stupid what's going on under the hood is and know to avoid it.

Dylan Murphy
Dylan Murphy

Dennis Ritchie and Ken Thompson were the first Pajeets.
We went to lunch afterward, and I remarked to Dennis that easily half the code I was writing in Multics was error recovery code. He said, "We left all that stuff out. If there's an error, we have this routine called panic, and when it is called, the machine crashes, and you holler down the hall, 'Hey, reboot it.'"

Christopher Clark
Christopher Clark

I don't think you understand how their implementation of abilities works. Your solution is more code, more files, and undoubtedly less efficient.

You keep using this joke as if it were the core design principle of UNIX. Tons of error recovery code is a waste of time, and bloat, unless you're writing a fault-tolerant financial system.

Ethan Evans
Ethan Evans

Because that defeats the purpose. The C++ people are saying that the language should do that for you. The C people argue that when the language does, unoptimized code is slow do to containing numerous operations that don't need to happen.

Take this code:

std::string makeString()
{
return "Hello";
}

int main()
{
std::string someString = makeString();
}

A C person looks at this and says: makeString() is going to construct a temporary string object, allocating memory for and copying "Hello". Then, it is going to pass that to construct someString, which will allocate memory for and copy "Hello" again. That's 3 copies of "Hello" in memory.

A C++ programmer will note that the lowest optimization setting will return-value optimize away one of those copies, and one can modify someString without the program dying.

The C code is error prone, and expert C developers have shown time and again that they don't actually have the discipline to write correct C, let alone C-with-ad-hoc-classes.
The C++ code requires optimization to have suitable performance, and attracts Java programmers (the number of corporations that use Java means that there are a lot of shitty developers who know Java).

The only problem I've had with this is that you complex ownership rules. I let STL containers copy my data because then I know that the container owns the data. And then the Java-trained junior devs won't create memory leaks when they manipulate the container.

Liam Perez
Liam Perez

Use asprintf()

Benjamin Rodriguez
Benjamin Rodriguez

QNX and MINIX3 are resilient enough for emdedded use though.

Blake Martinez
Blake Martinez

Pass pointers.

Asher Watson
Asher Watson

Suppose you want to create a select /where SQL query from. From isolated strings. What do you do? Allocate a new string and copy everything into it. You could have a fixed size static buffer (fast), but then you aprori limit query length, and waste arbitrary space extending that limit. How long is the longest query?

C++ you can concatenate strings. (which probably just invokes its version of memory mangement to malloc anyway).

Logan Peterson
Logan Peterson

My droog. asprintf is implict malloc.

but C++ strings probably implicit malloc anyway, i didn't know about asprintf, and it cleans up my code

Colton Ortiz
Colton Ortiz

If you're sending SQL queries, malloc() is not going to be your bottleneck (the disk and/or network are), so you might as well just malloc every query string.

Jonathan Myers
Jonathan Myers

I let STL containers copy my data
No, this is just bad. You have no excuse for this now that you have things like unique_ptr built in. Fix your code.

Juan Jones
Juan Jones

Your solution is more code, more files
True. Abstraction has a cost.
and undoubtedly less efficient
Untrue. I'd be able to avoid that massive number of comparisons they're doing by having some form of map.

Alexander Russell
Alexander Russell

Suppose you want to create a select /where SQL query from. From isolated strings. What do you do? Allocate a new string and copy everything into it.
It sounds like you're trying to solve a problem incorrectly and that's the cause of your shitty code. You shouldn't be assembling SQL query strings dynamically. It's not 1999 anymore. Query strings should be static and prepared. Dynamic arguments to queries should be passed via positional APIs. Queries that need to change depending on the situation should be handled by stored procedures plus positional APIs. Proper SQL has almost nothing to do with query strings these days, they're only used at startup.

Noah Roberts
Noah Roberts

This. Views, functions and prepared statements are your friends, and stop making your code vulnerable to SQL injection.

Owen Phillips
Owen Phillips

You can either use prepared queries and bind values, or you can quote any SQL metacharacters. It doesn't matter which one you do, so long as you do it correctly. I often use both, depending on what's easier.
But that's just for sanitizing user input. Optimization might have different needs, but it's not a given that everything has to be optimized with prepared queries. I've worked on projects where low volume transactions were the norm, and the business logistics made high volume basically impossible anyway. Everything depends on the circumstances at hand.

Grayson Barnes
Grayson Barnes

It doesn't matter which one you do, so long as you do it correctly.
It does matter. Passing dynamic query strings is inefficient as nothing can be cached, it's having to parse and replan queries all the time, and you're grinding user data through escaping which is both slow and extremely dangerous. Even good webdevs know not to do that so I can't call it webdev-tier.
sanitizing
That word even being in your vocabulary is a huge red flag. You mean 'escaping' in this context not 'sanitizing' but you've got a third world PHP Pro stink to you.

Bentley Wood
Bentley Wood

When your so abstracted away in your rails framework that you have no idea what the reality is.

Wtf. Ultimately, queries are dynamic. Why? Because we don't know apriori what to search the database for sc. If i knew apriori I was going to search the database for rows where firstname='example' . I wouldn't have a database. I would have a textfile with the values cached.

The second the query becomes dynamic (and useful) , you have string allocation issues in C. Why? Because libmysqlclient mysql_real_query takes a string argument. So ultimately, you, or some framework are going to malloc a string to go there, because C doesn't have string concatenation.

I wrote a wrapper function that is passed a hash and generates a syntactically valid SELECT/Where statement (thats sanitized) from pairs in the hash and a table name as an argument. But you still have to malloc the string.

If rails/nodejs whatever the fuck trend language your using now has a wrapper function to generate query strings from hashes (like I am dong anyway), know that its still allocating a new string, because ultimately, your using the C ABI on x86 which doesn't have string concatenation natively.

Your argument of just use rails is retarded.
Or I don't understand what your talking about

Sebastian Lee
Sebastian Lee

I don't know alot about C++ , but I just assembled this , and debugged with gdb, and it looks like main has a local variable someString ,which is passed as a pointer to makeString, which calls the C++ runtime to allocate a string at its address directly.

So, it seems this code doesn't 3 times. It copies "Hello" from .data to a string object once in allocating the string, directly where it belongs from makeString().


.file "test.cpp"
.section .ctors,"aw",@progbits
.align 8
.quad _GLOBAL__I__Z10makeStringv
.LC0:
.string "Hello"
.globl _Unwind_Resume
.text
.align 2
.globl _Z10makeStringv
.type _Z10makeStringv, @function
_Z10makeStringv:
.LFB1422:
pushq %rbp
.LCFI14:
movq %rsp, %rbp
.LCFI15:
pushq %rbx
.LCFI16:
subq $40, %rsp #Create locals No Locals! Yikes
.LCFI17:
movq %rdi, -32(%rbp) #save RDI (argument, pointer to local in main) to local
movq -32(%rbp), %rbx #move that same local to %rbx ??
leaq -9(%rbp), %rdi #load local variable address to %rdi (argument to new function)
call _ZNSaIcEC1Ev@PLT
leaq -9(%rbp), %rdx #Load address of another local into %rdx
leaq .LC0(%rip), %rsi #load address of SOMETHING? into %rsi
movq %rbx, %rdi #save old return value(address of someString local) of fn _ZNSaIcEC1Ev@PLT as %rdi (first argument)
.LEHB0:
call _ZNSsC1EPKcRKSaIcE@PLT #This inits string object, now data is contain in string.
#rbx now contains address of string
.LEHE0:
leaq -9(%rbp), %rdi
call _ZNSaIcED1Ev@PLT #what is this? #no return value. takes argument local variable.
jmp .L27
.L30:
movq %rax, -40(%rbp)
.L28:
movq -40(%rbp), %rbx
leaq -9(%rbp), %rdi
call _ZNSaIcED1Ev@PLT
movq %rbx, -40(%rbp)
movq -40(%rbp), %rdi
.LEHB1:
call _Unwind_Resume@PLT
.LEHE1:
.L27:
movq -32(%rbp), %rax
addq $40, %rsp
popq %rbx
leave
ret
.
main:
.LFB1423:
pushq %rbp
.LCFI18:
movq %rsp, %rbp
.LCFI19:
pushq %rbx
.LCFI20:
subq $40, %rsp #create local variables. only local variable is someString!! yikes. 40
.LCFI21:
leaq -16(%rbp), %rdi #load the address of local variable into RDI (argument to makestring)
.LEHB2:
call _Z10makeStringv #call makestring
.LEHE2:
leaq -16(%rbp), %rsi #load address of that local variable into rsi
movq _ZSt4cout@GOTPCREL(%rip), %rdi #some kind of local variable gaurd argument
.LEHB3:
call _ZStlsIcSt11char_traitsIcESaIcEERSt13basic_ostreamIT_T0_ES7_RKSbIS4_S5_T1_E@PLT //call
.LEHE3:
movl $0, %ebx
leaq -16(%rbp), %rdi #load address of local variable into rdi
.LEHB4:
call _ZNSsD1Ev@PLT
.LEHE4:
movl %ebx, -28(%rbp)
jmp .L31
.L34:
movq %rax, -40(%rbp)
.L32:
movq -40(%rbp), %rbx
leaq -16(%rbp), %rdi
call _ZNSsD1Ev@PLT
movq %rbx, -40(%rbp)
movq -40(%rbp), %rdi
.LEHB5:
call _Unwind_Resume@PLT
.LEHE5:
.L31:
movl -28(%rbp), %eax
addq $40, %rsp
popq %rbx
leave
ret

Parker Rodriguez
Parker Rodriguez

Did you even read my post you triple-decker nigger? I explained you don't always have to care about optimizing that stuff, and especially it matters jack all when the disk or network I/O is the bottleneck.
And any decent library has a convenient way to escape metacharacters, you don't have to do it by hand like a monkey. And if you weren't a monkey, you'd know that.

Eli Wright
Eli Wright

#what is this? #no return value. takes argument local variable.
It's the destructor for std::allocator<char>, apparently.

Also, looks like you forgot to add -O3 :^)

Blake Wood
Blake Wood

The second the query becomes dynamic (and useful) , you have string allocation issues in C. Why? Because libmysqlclient mysql_real_query takes a string argument.
You really need to learn how to use a database properly before writing a library for one as your head is full of rocks. Again, like I said, you don't use query strings anymore past startup. You use prepared statements of static strings:
https://dev.mysql.com/doc/refman/5.7/en/c-api-prepared-statements.html
And when queries do need to be more dynamic than the number of parameters you use prepared statements to stored procedures:
https://dev.mysql.com/doc/refman/5.7/en/create-procedure.html
It's a totally different protocol under the hood when you do this. Instead, you're forcing the thing to use a compatibility API from the '90s. Even the mistake that is MySQL has a C API like this but you should really be using PostgreSQL. But, baby steps.
Your argument of just use rails is retarded
I don't even know rails, I'm a C programmer. Get your head on straight, user.

James Foster
James Foster

I explained you don't always have to care about optimizing that stuff
No, you made an attempt to justify unsafe Pajeetcode. This was you:
can quote any SQL metacharacters
can quote any SQL metacharacters
can quote any SQL metacharacters
Disgraceful. A shameful display. Apologize to your father for disappointing him.

Brody Bell
Brody Bell

Prepared statements transmit data between the client and server using C language variables on the client side that correspond to SQL values on the server side. If there is a mismatch between the C variable type on the client side and the corresponding SQL value type on the server side, MySQL performs implicit type conversions in both directions.

Am idiot. Can confirm. Thanks for that. Wish I started with this API. First on the documentation is mysql_real_query . Fuck.

Writing it this retarded way was still insightful. I am glad mysql exposes another API.

Disable AdBlock to view this page

Disable AdBlock to view this page