#define alloc_stack(T) ((struct T*)header_init( \
(char[sizeof(struct Header) + sizeof(struct T)]){0}, T, AllocStack))
So far as I can see, there are basically no alignment guarantees here - the returned pointer to the char array is not guaranteed to be aligned properly for Header (which is a struct of a single void* field), nor is there any attempt to align T inside the array. If things get misaligned, on x86 and x64, it'll work (but possibly much slower than normal), but on e.g. ARM you'll get all kinds of weird things happening.Under ARMv8, I think alignment is less of an issue.
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc....
Another previous discussion: https://news.ycombinator.com/item?id=6047576
> It might be better to try Cello out on a hobby project first. Cello does aim to be production ready, but because it is a hack it has its fair share of oddities and pitfalls, and if you are working in a team, or to a deadline, there is much better tooling, support and community for languages such as C++.
Wow. Straight talk instead of salesmanship. High marks for that.
It's a pretty clever hack though, like using setjmp for exception handling. I'm pretty sure I'd never want to use that in production anywhere but it was probably fun to implement.
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
http://code.jsoftware.com/wiki/Essays/IncunabulumA I Sou
Just a few off the top of my head:
* No need to specify type. Use var.
* Simpler for loops
* Inbuilt types for Hash Tables
* File types, making file reading much easier
* Function types, making it easier to pass functions around
* Doctype access
* Threads & Mutexes
* Format strings
* GC (with ability to turn C-types into Cello-types for GCing.)
It is fundamentally syntax-sugar, but enough that what you end up with doesn't necessarily look like C at the end.
with(f in new(File, $S("test.txt"), $S("r"))) {
var k = new(String); resize(k, 100);
var v = new(Int, $I(0));
foreach (i in range($I(2))) {
scan_from(f, 0, "%$ is %$ ", k, v);
show(k); show(v);
}
}
(From: http://libcello.org/learn/file)I see types everywhere; they appear to just have been moved from the left-hand side to the right-hand side? eg:
var i0 = $(Int, 5);
var items = new(Array, Int, i0, i1, i2);It's higher level because it provides abstractions that improve the language's expressiveness.
You've really gone down the rabbit hole if you think GC is an improvment
I had thought about trying to make a type-safe version of Cello but I eventually realized that I can't do it in cpp so at that point it became its own language and too much work (I did not write Cello).
typedef void* var;
Cello is extremely impressive and could be fun for hobby projects, but for something you'd actually want to use on a real product you'd be better off just creating a new language (it could compile down to C even, like Vala did).Nim is another take on that particular strategy.
« In this talk I dig into the depths of my programming library Cello - a fun experiment to see what C looks like when pushed to it's limits. I'll cover how Cello works internally, some of the cuter tricks used to make it look and feel so different, what is in store for future versions of Cello, and why it is important to push languages to their boundaries. »
portability? stable ABI? ... writing something in C make it easy for any other higher level language to link to it. That's why we're not done with C, at all ... it's basically the only serious language out there used to share code among every possible platform or language. Even C++ which is a bit safer in practice is harder to link.
I just wished C was a bit safer by default (arrays with bound checking,...)
Not to go down the C++ evangelist route, but if you want to write libraries in C++ to use with other high level languages, you can wrap the headers in extern "C", and still write C++ as normal in your own code.
So aside from performance and legacy codebases, there's no huge incentive to start a project in C these days. I think those who do it, do it in spite of the alternatives out there.
Vala has an own seperate transpiler that generates C code from Vala code.
Cello uses the normal C preprocessor to generate C code.
C is my main language and I dabble in C++. I really dislike C++. I love C. I welcome any efforts to add a bit of higher level functionality to C. I have no desire (ever) to switch to C++.
That's not really true now is it? Sure, C++ and C are separate languages but they have a common history and everyone knows that. One can write extensive programs that are valid for both C++ and C compilers. C isn't a true subset of C++ but for from many practical perspectives it is. In practice they have a common ancestor language that still can be (more or less) compiled with both compilers.
Lisp and Python however... they have no such common ancestor and the syntax are very different.
Only if a python programmer was resorting to contrived macros to shoehorn some of Lisp's features onto python.
If a python programmer wants to write lisp in python, why not simply use lisp?
What about D? Rust?
C++11 and further can be fancy, and not be supported in every possible platform like exotic ones.
Bad reasons would be to talk about the gimmicks of C++, but generally it boils down to programmers being taught well about the language, because it's not an easy one to understand fully, as there many weird pitfalls.
C++ still has to fix some its flaws, like compile times (this should be improved with modules).
So to put it simply, you can still do good work with C because C compilers are just simple and straightforward. When you don't need C anymore (because you only use for it's size and speed, not for the high level), you use something more high level like python. C++ should allow programmers to do everything, but C++ is not perfect and not fully accessible to everyone.
The main reason I can think not to use C++ is that C has a simple stable ABI so you can easily use C libraries from many languages and compilers. But you can always wrap C++ libraries in a C API so that's not a huge concern. Just a pain.
So, this Iron language sounds like deja vu to me from two, different directions. I recommend against it.
You pays the Gold price, or the Iron price.
var i0 = $(Int, 5);
i0 = $(String, "Hello");
Perfectly valid.Which ones?
float i = 10;
DO({i+= 10;} 20);
will evaluate to this, modifying the "i" declared inside the macro float i_1 = 10;
{I i_2=0,_n=(n);for(;i_2<_n;++i_2){i_2 += 10;}} typedef long I;
#define DO(n,x) {I i=0,_n=(n);for(;i<_n;++i){x;}}
(I added a comma here after the }, 20 is the x parameters) DO({i+= 10;}, 20);
expands to: typedef long I;
{I i=0,_n=({i+= 10;});for(;i<_n;++i){20;}};
The '20' presumably should have been some kind of function call or action to repeat and the 'n' should have been the count (the reverse from your example).So that would make this:
typedef long I;
{I i=0,_n=(20);for(;i<_n;++i){ i+= 10; }};
You're still right that it will shadow any 'i' declared outside and so it won't work but it will not overwrite it as far as I can see. You'll just end up right where you started.What I really don't get is if they're going to use _n for the count anyway why not count it down to 0, that way the whole 'i' could be avoided.
(you'd still have a problem with _n but that could be overcome with a convention, which of course someone will forget with some nasty bug as a result)
https://github.com/django/django/blob/master/django/db/model...
The point is that building blocks that you get from C++ are higher-level even so - classes, operator overloading, template metaprogramming etc - which should make it possible to implement something like Cello with a lot less effort (and hacks).
I beg to differ. C++ encourages placing more code than strictly necessary into header files. Even the standard headers such as <algorithm> add considerably to the compile time, and they keep getting larger with every revision of the standard. When you are making incremental changes, it accumulates to a lot of time spent waiting.
C++ modules, on the other hand, will be like precompiled headers done right. If they ever get standardized. They didn't make it into C++17, and the prototype implementations in Clang and MSVC are incompatible with each other, but I guess it'll happen someday…
Variable x, y, z;
solver.add(x <= y);
solver.add(z >= x - y);
But if you need it in meta-way (and I always do, I rarely write non-meta code), you have to unwind all the sources[-in-headers] to find out what Expression is, how does one construct one, write dynamic expression builder, etc. Sources do consist mostly of one-line helper methods/getters/constructors that are nested and intercalled 10-15 times per operation. LPSolve was much simpler in API, since you don't mess with variables and add constraints directly as matrix values. double row[size+1] = { };
/* ...fill row... */
add_constraint(solver, row);
/* ...fill row... */
add_constraint(solver, row);
In the end of the day, both libraries involve identical usage pattern, but for C++ I have to create a convenience unwrapper. This 'convenience' swamp is SO popular in C++. Once you say "++", you have to deal with it all the time, unless you write something really dumb and straightforward. Not to mention most libraries have huge header-only parts due to template obsession. Qt, yeah. It takes forever to compile 20 modules on reasonably priced laptop even with fine-tuned prefix header and -j9.From the employment point of view, C++ is a nightmare. No one really knows it, and everyone thinks he does. Experienced developers can't tell what explicit constructor is, are confused with move semantics, blink hopelessly on "what is RVO". You actually employ python programmers for sky prices, while all they know is easiest part of C++/stl magic, which is effectively beginner-grade python with low-level bugs and UBs.
>wrap C++ libraries in a C API
Together with "ecosystem" such as std::cool_ptr<std::map<std::bar,std::baz>>. That's a concern.
When I want nice bridgeable object model above C, I use Objective-C or simple embedded language with proper features. Personally, I'm really tired of C++ everywhere.
[1] http://stackoverflow.com/questions/4489012/does-c-have-a-sta...
We use precompiled headers on a large project, we've never had any issue with them (MSVC and GCC)> Care to elaborate on the limitations?
want to elaborate? i use MSVC's implementation and never encounter any problems with it. then again, i also don't work on large projects, so i would like some insight.
I'm not an Iron zealot but I do believe that there rarely is such a thing as bad publicity :)
Example: https://sjobs.brassring.com/TGWebHost/jobdetails.aspx?jobId=...
At that time mixing C and C++ was trivial, especially because C++ was still quite simple and the C compiler was the target.
But after that things got more complicated. C evolved, several times in fact since that time and the C++ standard evolved as well. Leading to the impression that C and C++ are merely the old and the improved version of C but it is probably much better to think of them as two distinct species that share a common ancestor, where one of the two had some very radical mutations.
Contact Pro IT Recruiting where we know our candidates, Referral bonuses too!
$ cat foobar.c
#include <stdio.h>
struct foo {
int x;
int y;
};
int foobar(struct foo *f)
{
return f->x + f->y;
}
int
main(int argc, char *argv[]) {
(void)argc; (void)argv;
printf("%d\n", foobar(&(struct foo){10, 20}));
return 0;
}
$ gcc -Wall -Wcast-align -Wextra -pedantic -std=c99 foobar.c -o foobar && ./foobar
30
$ g++ -Wall -Wcast-align -Wextra -pedantic foobar.c -o foobar && ./foobar
foobar.c: In function ‘int main(int, char**)’:
foobar.c:17: warning: ISO C++ forbids compound-literals
foobar.c:17: warning: taking address of temporary
30
$ # taking address of temporary means that it's undefined behavior
[0] https://gcc.gnu.org/onlinedocs/gcc/Compound-Literals.htmlstruct Foo { int virtual; };
C99 native complex numbers
In C++, everything is an int; except for objects; and templates; and lambdas; and classes; and exceptions; and all the other things which keep getting chucked on to the pile.
I like languages with a clear, simple concept behind their operation: lambda calculus, combinatory logic, Scheme, Forth, Joy, Pure, etc. C is a bit gnarly, but passable. C++ is horrible.
Horrible, horrible code.
You can write clean C without casts and treating everything as an integer, but you have to start your code with that goal.
That said, I would argue that minimal explicit casts is a pretty good goal for any C programs - I find that crazy casting tends to be a sign something could be done better. But obviously, casts are definitely necessary in some instances, so it's not like "castless" code is guaranteed to be the right way to do things anyway.
I don't understand this. Floating point values aren't ints. I suppose strings are integers because they're made up of 8-bit chars (which are basically ints), but I don't understand how that is advantageous or helpful.
So, for example, you know if at offset 0xDEADBEEF there is are 8 bytes which are holding a number that you want to use, you can access that chunk of memory and use it however you want. And you can interpret it how it is appropriate for your use case, for example reading it into a string, or an int.
Being grounded in hardware makes a lot of other stuff quite arbitrary, and it can become a question of style rather than functionality. And by imagining what the hardware is doing you can understand what code is doing that you have never seen before at the lowest levels (all the way to what the registers, FPU, APU, etc on the CPU are doing). That can also help with debugging.
So you dont like C because Undefined behaviour complexitys. Im confused now.
Undefined behaviour, declared as in a language standard, isn't too bad; it might forbid some potentially-useful combinations of expressions, but there'll usually be a workaround.
The problem is compilers which allow undefined behaviour by default, rather than aborting with a helpful error message. This puts the burden of avoiding undefined behaviour on the programmer, which is really bad. This might be unsolvable for C, due to the nature of its particular undefined behaviour.
For brand new languages, I'd recommend minimising undefined behaviour as much as possible, but definitely ensure that any that remains can be found statically!
The aspect that I love about C is how easy it becomes to read. C offers a (arguably) nice programming interface while not allowing the programmer to hide very many things that are going on. C allows you to make nice abstractions, but those abstractions are still built upon the same basic concepts that C supports, and these abstractions generally don't fundamentally change how the language works, so you can very easily tell the control flow of your program if you simply understand the interactions between the basic parts in use.
Now that said, I'll be the first to say that I think C could benefit from a variety of different features (Some from C++, some from others, and some unique to C), and I could easily give you a fairly long "wish-list" I have for C. But, the clear nature of C is a huge advantage that I think is underrated, and is something that you really can't get back in a language once you lose it.
When you (or I) read a piece of C++ code, there are a lot more details you have to take into account then when you read a piece of C code, simply because C would force the writer to be more explicit in what they are doing in those cases.
Again though, I'll make it clear that I don't think C is the be-all end-all of languages - in particular I'm excited to see how Rust goes - but I do think it has traits that are very nice but largely ignored in most of the current languages in favor of adding lots of different ways to write your code.
Pure C with few macros is quite refreshing to read. But it can get hairy quite quickly.
I meant "fewest possible abstractions over the underlying hardware".
BF and Lisp are both much simpler than C, but don't fit what I was trying to get at, as they present a totally different abstraction that is actually quite different from the underlying hardware.
(Actually, so is C, since assembly language is itself an abstraction and processors work much differently than they did in the 70s and 80s... but as a programmer, and not a hardware engineer, I consider asm to be the baseline, zero-abstraction level ;) )
I didn't mean "C is nice because I can just write 'int' for all the types and it works", I meant "C is nice because it represents data in a very conceptually uniform way: either as integer, or 'pointers' which are themselves integers."
The current world population is an integer, my bank account number is an integer, but that doesn't make it's meaningful to add them together. Values can have the same representation without being the same type :)
> "Everything is an int" is not a good way to be thinking about things. There's a reason that `intptr_t` exists.
From http://en.cppreference.com/w/c/types/integer (top Google hit for `intptr_t`):
intptr_t
integer type capable of holding a pointer
They're integers :)> Well written C shouldn't rely on any integers being specific sizes or the same size unless you're using the standard types for that purpose (Llke `uint8_t`, `uint32_t`, etc.).
I never said it should; but from that same cppreference site:
int8_t, int16_t, int32_t, int64_t
signed integer type with width of exactly 8, 16, 32 and 64 bits respectively
These are also integers :)> you should basically never be casting integers into pointers
Again, I never said you should. I didn't say, or mean, anything about casts.
[1] https://github.com/spc476/SPCDNS
[2] https://github.com/spc476/SPCDNS/blob/ca5052c3d0c3252071a18e...
[3] I am NOT a fan of C++.
[4] But I had to anyway, but I used the C pre-processor to rename the field.
Also, much C code is still valid C++. Sure, you can write code that isn't, but I would guess (pulls a number out of nowhere) that 90% of the valid C code is also valid C++.
That makes them languages that have separate standards, but not completely independent standards, that share a whole lot of source code. That's something less than fully separate in my book.
Better examples (of actually useful things) would be things like designated initializers, struct literals, declaring array lengths in args using static, etc.
int *x = malloc(sizeof(int));He's saying that C is simple because it offers a small set of mostly orthogonal features. You get structs, functions, pointers and integers, basically. You don't even have opaque 'String' types or any of that. It's all simple, orthogonal bits.
In C, if there are no macros involved, everything you read in code is arithmetic, function calls or pointer dereferencing. There is no overloading, there are no automatic secret implicit constructors, there are no destructors, no garbage collection, etc.
C++ has a huge amount of behaviour, a lot of it very abstract compared to C. For example, vtables. How are they implemented? That isn't clear at all from reading C++ code. You have to go look at the generated code. If there are vtables in C you have explicitly written
struct vtable {
foo_function *foo;
bar_function *bar; };
struct a {
struct vtable vt;
...
};I was talking about how C++ requires more communication with your team, because some "abstraction" features you might not want (RAII, RTTI, polymorphic dispatch, templates, exceptions) are a lot more easy to introduce than with C.
Except these days with strict aliasing that's not true. If you access memory through a pointer of the wrong type, you've probably committed the crime of undefined behavior, for which the compiler might punish you by breaking your code - but probably won't, leaving the bug to be triggered in the future by some random code change or compiler upgrade that creates an optimization opportunity.
Admittedly there are ways to avoid undefined behavior, but still. C gives the compiler a lot of leeway to mess around with your code.
Essentially, what strict aliasing rule requires is that user cannot go crazy casting pointers. Casting float pointer to int pointer is completely wrong. The exception is that it's completely safe to cast values to char pointer or void pointer (and back, but only to original type of a pointer). Objects of different types cannot use the same memory area.
What this usually affects is code that parses external data into a structure. This can be dealt with by use of `memcpy` (to copy data from char array into a structure) instead of pointer casts, which is mostly safe as far C specification is concerned (mostly because C specification doesn't really define stuff like paddings, so you need to be careful about that). There is also an option of using `union` which is allowed by C11 specification (but compilers released with C11 that had strict aliasing optimization didn't break code that had aliasing through union and even documented that).
Of course, you've got me, it only breaks existing code, and doesn't affect code that's written perfectly according to the rules of C and not peoples' intuitions about what pointers actually mean on a hardware level.
It's not even safe to do this:
struct a {
int x;
};
struct b {
int x;
int y;
};
struct b b;
struct a *a = &b;
You have to write b like this: struct b {
struct a inner;
int y;
};