Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> As in, a person who has used and learned a dozen plus languages but only tacitly used C++ suddenly will be a complete invalid when trying to write in C++?

I've switched at least 5 languages professionally and used probably 5 more for extended periods of time and wrote a decent chunk of C++ "back in the day". I'd say C++ is the least suitable for "learn on the job" approach out of any language I can think of (I'm lumping C in there) - soo many footguns all over the place and very little to guide you to the right path.

They are at fault for even starting the conversation without making it obvious is a hard requirement.



I generally agree with you, but I think it depends on the team. If the team is just "using" C++ but aren't good software developers, then yea, I totally agree that having a non-C++ expert join the team is going to be a rough ride for everyone. But if the team's software architecture and coding practices are solid, which probably means they use a subset of C++'s vast feature set in a very clear way, then one probably could jump in just fine.

In a way, them only accepting in C++ experts probably means they're either doing something actually very complex with regards to C++ itself or their code quality is a shitstorm.

> They are at fault for even starting the conversation without making it an obvious deal breaker.

That is definitely my feeling. My resume is quite clear about my experience and tools.


The problem with C++ is you just don't know what you don't know. But you know there is a lot of it. A good framework certainly helps but it doesn't solve this basic problem.


I think by the time you’ve learned 12 different languages you’ll realize when something is hard enough that you need to take a step back and read some stuff first before diving in.


Nice that you mentioned it. Just a few weeks ago I didn't even know abstract syntax trees, AST's, existed, and I had that exact experience in order to build some stuff that works with them.


"But if the team's software architecture and coding practices are solid, which probably means they use a subset of C++'s vast feature set in a very clear way"

So... C? =P

Sorry. But my point is I think there's really very very few C++ places that could say their code is described by your statement. Not helped by the fact that I think there's really very very few C++ places at this point in the first place.


> So... C? =P

Without the string handling API, the always unsafe casts or the global states hidden in its standard library, the complete lack of automatic memory management, ... . Most of the bugs I run into in badly written C++ code turn up in places where someone had the bright idea to go C without good reason.


There still are places slowly enhancing their C codebases with C++.


There are a small number of high-end software firms doing this. "slow-enhancement" generally translates to "maintenance". The exception to this are a few prominent mega-caps.


> In a way, them only accepting in C++ experts probably means they're either doing something actually very complex with regards to C++ itself or their code quality is a shitstorm.

If you aren't doing something complex then you aren't needing C++ today, just use Rust then.


I once jumped into a C++ low level dev role having not written C++ in 20yrs (as a teen writing video games).

I think the benefit of experience as the OP is that you have a general understanding of the scope of languages, complexity and how to seek out answers.

I found that focusing on writing modern (as modern as was allowed) code using the most up to date patterns and methodologies meant that my code was generally better than peers that had been hacking C++ for 10yrs but developed bad habits or simply preferred riskier styles of coding.

I don't think C++ is special in being "hard". In fact, the language is so flexible that you can use one of a myriad paradigms that allow for fairly hassle-free coding.

The complexity is usually around the constraints of what you're coding because if you're writing it in C++ it's probably meant to be tiny, fast and memory efficient. That also implies that the problem itself is one that lends itself better to reasoning around as opposed to 42 levels of inheritance in a Java system.

I don't think _every_ developer could switch to C++ but if one of your say 5 languages is unmanaged then it's not rocket science making the switch.


Same. I wrote C++ "professionally" for ~5ish years out of my 25 year career and would only consider myself a novice in the language.


Been doing C for forty years and feel the same.


Beginner: I have so much to learn ...

Intermediate: I know everything!

Expert: I have so much to learn ...


> I'd say C++ is the least suitable for "learn on the job" approach out of any language I can think of

Anecdote: I've got a couple languages and decades under my belt, and a very simple C/C++ Arduino project is making me doubt my sanity. Ex:

    Serial.printf("%s", String("Hello world...")); // Emits 4 nonsense bytes... But shorter literals work fine.
________________________

EDIT: To save readers some time--I didn't intend to nerd-snipe [0] y'all, honest!--the answer has been found, and it is probably:

    Serial.printf("%s", String("Hello world...").c_str() );
The shorter payloads like "Hello World" happen to give the desired results only as an accident of optimization code.

[0] https://xkcd.com/356/


Your problem is that whoever designed that Serial class is incompetent and should be shot and their body defiled in unspeakable ways.

The C-language varargs concept and the C++ object model are not compatible. C++ provides varargs only for backwards compatibility with legacy C libraries. New APIs written in C++ should not be using it because passing a C++ object through it is undefined behaviour. No amount of rationalizing (as all the comments downthread are doing) is of any value: undefined behavior is undefined.


Yet GCC will still apparently let you call this function without as much as a warning. This should be one of the easiest mistakes to find statically.

Clang at least errors out here.

C++ is a mess.


Well, if the designer of the class used the right annotations GCC will issue a warning if warnings are enabled. This is third-party code and nothing to do with GCC per se and the language itself does not require any kind of compile-time warning for undefined behaviour. Then again, most people seem to disable or ignore the warnings the toolchain gives them. You can make anything idiot-proof but there's always a bigger idiot.

It sounds more like a crappy library designed by people who don't know their craft. It's easier to blame the tools.


It’s Arduino so it’s C++ through the looking glass. Some unusual choices about core classes and syntactic sugar via a bit of preprocessing, plus the opaque error messages and core dumps we all know and love, but on a tiny device with a serial connection.


Is it even possible to core dump on AVR, with no storage and MMU?


Seg fault, I guess? It’s been a while.


AVR has no protection and no segments. I mean really, it seems to be true that new generation of programmers have zero understanding of hardware, nothing personal.


Nothing personal taken. If I was something more than a hobbyist wrt to hardware, then I might.

I was having this conversation with someone the other day regarding GenAI. The expectations for understanding the lowest-level concerns have changed generationally. Today's hardware wizard might prize their old-school understanding of fundamentals but would probably be rubbish in 1948.


It is completely legal to pass a C++ object through varargs.


Will gcc catch that? The GCC compiler knows about "printf" as a special case. But "Serial.printf" may not have a definition with the annotation GCC needs to check parameters.


also avr-gcc is several major versions behind, isn't it?


Since it's using the String class, this is likely not being compiled by avr-gcc. Or at least I hope OP isn't being so masochistic as to try to use String on a Mega328.


you're right, it turns out it's an esp32


I imagine you got that code snippet(or a similar example) from somewhere but to me the fairly obvious problem is the chafing between the C and C++ world. %s is for C style strings and I have to imagine that printf function is in the C world. The String(“Hello world…”) is an object in C++ world so expect weird behavior when you try to combine them. As you say in your edit, SSO will make this even weirder.


Random 4 bytes sounds like reading a pointer as something else, shouldn't be too hard to debug.


If you're really asking about that code snippet...

I don't know that library, but have you tried this?

  Serial.printf("%s", "Hello longer world");


Oh, that works, but the Arduino String library had some features I wanted. Its docs have an explicit example of putting a literal (an even longer one) into the constructor, so... Mysteries!

My default expectation is that it is a footgun that I do not understand.

The alternative is that I've stumbled across a very rare bug in some popular libraries, or else my hardware is cursed in a very specific and reproducible way.


Looking at [0], I see a "c_str()" method. Maybe give that a shot?

  Serial.printf("%s", String("Hello world...").c_str());
I actually don't see a "Serial.printf(...)" method in these docs [1], but I do see it here [2]. I'm not sure I'm looking at that right docs for your library though.

[0] https://www.arduino.cc/reference/en/language/variables/data-...

[1] https://www.arduino.cc/reference/en/language/functions/commu...

[2] https://docs.particle.io/reference/device-os/api/serial/prin...


Just to answer the mystery, it seems the foot-gun is that smaller String()s appear to work "by accident" due to an optimization, and I have to call a method on the String object before passing it onwards. [0]

> I actually don't see a "Serial.printf(...)" method

I think it's coming from the ESP32-specific libraries. Some cursory searching didn't find the spot, but it may be some magical preprocessor directive stuff.

[0] https://github.com/espressif/arduino-esp32/blob/7a82915de215...


Maybe what's happening is the `printf` function is interpreting the memory address of the `String` object as if it were a pointer to a char array. This leads to it printing seemingly random bytes (which are actually parts of the `String` object's internal data structure) instead of the string content you expect.


This sounds kinda plausible.

IIRC, some string implementations have separate implementations for very short strings vs. longer ones. Similar thing for vectors.

I also see some size-related logic in the (current?) String implementation [0] [1].

String is a class with no virtual methods, and its first data member is a pointer to the underlying buffer [2]. So if Stream.printf unintentionally type-puns String to char*, it might work out okay?

[0] https://github.com/arduino/ArduinoCore-API/blob/master/api/S...

[1] https://github.com/arduino/ArduinoCore-API/blob/master/api/S...

[2] https://github.com/arduino/ArduinoCore-API/blob/cb3ab4c90d71...


Although sizeof(String) > sizeof(char*), so any subsequent arguments to printf(...) would probably be screwed up.


Thanks, yeah, that seems to match this SO answer [0] which refers to some "small-string optimization" in the ESP32 libraries [1].

So basically the foot-gun is that smaller String()s appear to work "by accident".

[0] https://arduino.stackexchange.com/a/90332

[1] https://github.com/espressif/arduino-esp32/blob/7a82915de215...


It gets worse.

You're only printing 4 bytes because your string is sufficiently short, and the next byte it's reading is 0, since your capacity is small.

If your string were about 17 million bytes long (0x0101'0101 == 16843009 is the first value that causes problems), then your address, capacity, and size would all likely be nonzero, in which case your Arduino would just keep printing bytes until it lucked upon a zero, or overran its buffer so badly that it started trying to read different segments of memory and eventually segfaulted.


> your Arduino would just keep printing bytes until it lucked upon a zero, or overran its buffer so badly that it started trying to read different segments of memory and eventually segfaulted.

I don't think I've ever used an arduino core for something that had an MMU. It should happily keep printing all the way until the end of memory, and either stop there because it's zeros after, or wrap back to the start depending on the board. I have written code to dump out every byte in memory over serial before, just for kicks.


This is more of a C question than C++.

In a C++ library you would probably make the format function type safe. But both Clang and gcc have annotations you can add to functions using format strings so they are type-checked


eh forget all this coding minutiae, i dabbled with arduino here and there.

in my experience it's not to do with code. your serial/usb runs the bytes back through your debugger (typically IDE On the PC). Your IDE has config settings like baud rate +/- encoding that you have to config. If that IDE config is messed up (IDE Is presumably printing out your printf bytes over usb or whatever), then your output is bytes. Make sure your baud is correct.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: