Code doodles #3 – significant parentheses, C++14 style

0
Filed under Programming
Tagged as , ,

Hello, everyone. It has been a while since my last post.

While watching CppCon 2014 I found this little gem being described by Scott Meyers.

Consider the following code:

decltype(auto) foo()
{
	static int Foo;
	return Foo;
}
 
decltype(auto) bar()
{
	static int Bar;
	return (Bar);
}
 
int main()
{
	decltype(auto) a = foo();
	decltype(auto) b = bar();
	a++;
	b++;
	cout << foo() << ", " << bar() << endl;
}

Would you expect this to print 0, 0? Well, not so fast. decltype(auto) is just a nicer syntax for decltype(name), where name is “unparenthesized id-expression or an unparenthesized class member access”, as described here. Therefore it follows the same rules.

That’s another corner case to remember, but I guess it could also make a nifty party trick, if one can find the right party.

Code Doodles #2 – the quirky switch

0
Filed under Programming
Tagged as , ,

According to grammar rules defined by the C++ standard (and C as well) the following code is valid:

switch(i) i++;

This peculiar statement has no effect, other than confusing the potential reader and possibly counting as an assertion that increment is indeed possible for i, although the point of using such a switch statement for static assertions eludes me.

The rules that allow this:
switch statement:

§6.4 Selection statements
switch ( condition ) statement

where statements may be one of the following:

§6 Statements
statement:
labeled-statement
attribute-specifier-seqopt expression-statement
attribute-specifier-seqopt compound-statement
attribute-specifier-seqopt selection-statement
attribute-specifier-seqopt iteration-statement
attribute-specifier-seqopt jump-statement
declaration-statement
attribute-specifier-seqopt try-block

Where our i++ is such a statement.

In the same vein the following code compiles:

#include <iostream>
#include <iomanip>
 
int main()
{
	int i = 0;
 
	switch(i){
	i++;
	case 0: i++; break;
	default:;
	}
 
	std::cout << i << std::endl;
 
	return 0;
}

As expected, the first i++ is not – and, in fact, cannot be – executed, because there are no labeled statements associated with it.

It could probably be called an oversight of the standard, but it’s hardly a popular problem, so I doubt there’s reason to complicate parsing rules even more. And if you ever see this during a code review, kill it with fire, as quaint as it is.

Stop assigning string literals to char* already!

2
Filed under Programming
Tagged as , , ,

Every now and then I see people writing C++ code containing heresy in the vein of the following:

char * foo = "bar";

This is no more legal C++ than

const int qux = 42;
int * quux = &qux;

It is not undefined, unspecified or implementation defined! It is simply illegal (and conveys false intent: char* implies modifiable string). It should simply not compile, though right now all the major compilers let you get away with such a conversion – but they may (and should) stop that at any time.

It is valid in C (C89 through C11), although assigning to a string literal is undefined behaviour there. C++, however, has deprecated this conversion since C++98.

C++03 §4.2/2 (conv.array/2)
A string literal (2.13.4) that is not a wide string literal can be converted to an rvalue of type “pointer to char”; a wide string literal can be converted to an rvalue of type “pointer to wchar_t”. In either case, the result is a pointer to the first element of the array. This conversion is considered only when there is an explicit appropriate pointer target type, and not when there is a general need to convert from an lvalue to an rvalue. [Note: this conversion is deprecated. See Annex D. ]

In fact, the original proposal would be old enough to buy alcohol around the world this year, USA included! In my opinion, more than enough time has passed to phase out that “feature”. The C++ Standards Committee seems to agree, as C++11 doesn’t list such conversion at all (conv.array has only one sub point) and, in Annex C, says the following:

C.1.1 Clause 2: lexical conventions [diff.lex]
/…/
char* p = “abc”; // valid in C, invalid in C++

In C++, we’re years past writing such code (I hope). If you need a modifiable string, initialize an array or use std::string:

char foo[] = "bar"; 		// ok
std::string qux = "quux";	// ok

and if you don’t need to modify, for the sake of your co-workers (if not your own), don’t break const-correctness and use:

char const * foo = "bar"; 	// ok

Code Doodles #1 – this code is legit… again

1
Filed under Programming
Tagged as , , , ,

The following is a legit, albeit a little obscure, C89 program. It is also a legit C++11 (and above) program.

int main(void)
{
	auto a = 42;
	return 0;
}

In C89, auto is used as storage specifier and a‘s type is (implicitly) int. C++ and C (beginning with C99) forbid implicit int declarations, but C++11 changes the meaning of the keyword auto from an automatic storage specifier (which is, conveniently, the default in function scope) to automatically deduced type. 42 is an integer literal (and a pretty good answer, from what I understand), so the deduced type is int (also C89′s default). The following table describes how different versions of C and C++ interpret auto a = 42; in a function scope:


C89 C99 C11 C++03 C++11
Storage specifier explicit auto* explicit auto* explicit auto* explicit auto* implicit auto
Type implicit int none none none automatically deduced int
Result int with automatic storage duration code incorrect code incorrect code incorrect int with automatic storage duration


*also the default

In the end, it means the exact same thing in C++11 and C89, but for completely different reasons.

Readable function pointers

0
Filed under Programming
Tagged as , ,

Consider the following declaration

char*(*(*foo)(int(*)(char*,char*)))[]

It’s artificial (generated with the ever-helpful geordi bot), although I’m sure that if you looked hard enough, a similar one would appear somewhere in the wild. In the above case, foo is a pointer to function taking pointer to function taking char* and char* and returning int returning pointer to array of char*. I think that even seasoned C and C++ programmers will agree that this is quite confusing at first glance. Or second. And third. Especially for people less versed in “C gibberish”, as cdecl.org aptly calls it.
Read More »