Am I being too C++ like?

I

Ian Collins

In many cases a well_chosen name can actually _add_ some information. Consider
something like:

typedef unsigned int ipaddr_t;

and speculate what variables of this type are used for.

PS. Target platform allows the assumption sizeof(unsigned int)==4.

Why assume?

typedef uint32_t ipaddr_t;
 
S

Stephen Sprunk

Why assume?

typedef uint32_t ipaddr_t;

That won't work; IP addresses can be 128 bits, so that should be
"typedef uint128_t ipaddr_t;".

Kleuske must have a system with CHAR_BIT>=32, which is the only way his
ipaddr_t can hold any IP address _and_ sizeof(unsigned int)==4 can be true.

If you incorrectly assumed an IP address was always 32 bits, though,
this shows yet another benefit to using typedefs to reflect the logical
data type: it helps you find (and correct) all the places in your code
that only work with IPv4.

S
 
I

Ian Collins

That won't work; IP addresses can be 128 bits, so that should be
"typedef uint128_t ipaddr_t;".

An IPv6 address is a completely different beast from an IPv4 (commonly
known as just IP) address. It's common (almost ubiquitous) to use a
typename like ipaddr_t to refer to an IPv4 address and a different
represent ion for an IPv6 address.
 
E

Eric Sosman

That won't work; IP addresses can be 128 bits, so that should be
"typedef uint128_t ipaddr_t;".

Kleuske must have a system with CHAR_BIT>=32, which is the only way his
ipaddr_t can hold any IP address _and_ sizeof(unsigned int)==4 can be true.

If you incorrectly assumed an IP address was always 32 bits, though,
this shows yet another benefit to using typedefs to reflect the logical
data type: it helps you find (and correct) all the places in your code
that only work with IPv4.

"All" is over-optimistic, I think. A difficulty is that
typedef aliases are in fact just aliases, not types in their own
right. Given `typedef int Foo;' and `typedef int Bar;', I still
have only the single type `int', not three types. For example,
I can pass a `Foo*' argument to a function's `Bar*' parameter.

Add C's promiscuity about silent conversion between numeric
types, and a typedef-aliased scalar turns out to be a rather weak
enforcer of purity. IP addresses may start out in `ipaddr_t' places,
but they won't stay there: By the time the code base gets to version
2.0 (maybe even 1.5), you will inevitably find "leakage" into types
not so helpfully named. If the compiler doesn't forbid something,
some programmer will do it.

Structs (and unions), by contrast, offer more in the way of
enforcability. If you make the `ipaddr_t' some kind of a struct,
the compiler will object to any attempts at smuggling it around as
some other struct, even a struct with the same element types and
layout. It's still not 100% bulletproof because `void*' is nearly
as promiscuous as numeric types are, but you'll get considerably
better "coverage" against type leaks.
 
K

Keith Thompson

Stephen Sprunk said:
That won't work; IP addresses can be 128 bits, so that should be
"typedef uint128_t ipaddr_t;".

Kleuske must have a system with CHAR_BIT>=32, which is the only way his
ipaddr_t can hold any IP address _and_ sizeof(unsigned int)==4 can be true.

Obviously that refers to IPV4 addresses, which are 32 bits.
If you incorrectly assumed an IP address was always 32 bits, though,
this shows yet another benefit to using typedefs to reflect the logical
data type: it helps you find (and correct) all the places in your code
that only work with IPv4.

Do you know of any systems that support uint128_t?
 
K

Keith Thompson

William Ahern said:
GCC has __uint128_t and __int128_t on a few platforms, but there's no
typedefs for uint128_t or int128_t. And there's no UINT128_C, INT128_C, or
equivalents, which makes it difficult to use 128-bit constants.

I hope Kaz is aware that I won't necessarily see anything he posts
here, even if it's a direct response to something I posted, since
I killfiled him a couple of months ago.
 
K

Kleuske

That won't work; IP addresses can be 128 bits, so that should be
"typedef uint128_t ipaddr_t;".

Kleuske must have a system with CHAR_BIT>=32, which is the only way his
ipaddr_t can hold any IP address _and_ sizeof(unsigned int)==4 can be
true.

The object of the little example was to show how a typedef alias can benefit
treadability of code. Its intention was _not_ to provide a watertight
solution portable over ipv4 and ipv6 architectures, but to illustrate a
point.

I am sorry if you missed that.
 
J

Jorgen Grahn

But if I create a new typedef T, and then declare:

T a;

I can't see at a glance whether T is a number, struct, and anything else.
That seemed to be the point of JG's remark. In this case it *does* hide some
information.

I haven't followed your reasoning, and haven't yet read the followup
postings. But the thing is: I avoid creating typedefs for /anything/
in C. I may use them as convenience aliases within a translation
unit, but that's about it.

(I use typedefs in C++ though, but they are more well-behaved there
for various reasons.)

/Jorgen
 
K

Kenny McCormack

Keith Thompson said:
I hope Kaz is aware that I won't necessarily see anything he posts
here, even if it's a direct response to something I posted, since
I killfiled him a couple of months ago.

Only total dorks feel the need to tell people who they've killfiled.

Kiki fits the bill admirably.

--
"The anti-regulation business ethos is based on the charmingly naive notion
that people will not do unspeakable things for money." - Dana Carpender

Quoted by Paul Ciszek (pciszek at panix dot com). But what I want to know
is why is this diet/low-carb food author doing making pithy political/economic
statements?

Nevertheless, the above quote is dead-on, because, the thing is - business
in one breath tells us they don't need to be regulated (which is to say:
that they can morally self-regulate), then in the next breath tells us that
corporations are amoral entities which have no obligations to anyone except
their officers and shareholders, then in the next breath they tell us they
don't need to be regulated (that they can morally self-regulate) ...
 
K

Kaz Kylheku

GCC has __uint128_t and __int128_t on a few platforms, but there's no
typedefs for uint128_t or int128_t.

typedef __uint128_t uint128_t;
And there's no UINT128_C, INT128_C, or
equivalents, which makes it difficult to use 128-bit constants.

#define UINT128_C(X) ((uint128_t) (X))
 
M

Malcolm McLean

The key point is because of a lack of language support, OO C doesn't
look like C++.  The question could have been "Am I being too Java like?"
Java's a more pure OO language than C++. But C++ is similar to C. C
compilers usually ship with a C++ compiler, and C++ compilers always
have either a C mode or a twin C compiler. So normally my advice to
someone trying to write OO C would be to go to C++. Going to Java
might be a better bet, but raises very many other issues, for instance
the Java swing library looks different to the C/C++ GDI library on
Windows.
 
I

Ian Collins

Java's a more pure OO language than C++. But C++ is similar to C. C
compilers usually ship with a C++ compiler, and C++ compilers always
have either a C mode or a twin C compiler. So normally my advice to
someone trying to write OO C would be to go to C++.

That is reasonable advice. But often circumstances prevent the
introduction of C++ into a C project. But the point still remains that
OO C isn't C++ like, it's how not to write OO in C++ like!
 
B

Ben Bacarisse

Kaz Kylheku said:
typedef __uint128_t uint128_t;


#define UINT128_C(X) ((uint128_t) (X))

I don't see how that is supposed to work:

#include <stdio.h>

typedef __uint128_t uint128_t;
#define UINT128_C(X) ((uint128_t) (X))

int main(void)
{
uint128_t j = UINT128_C(0x10000000000000000ULL);
puts(j ? "ok" : "fail");
return 0;
}

prints "fail" (with a compiler-time warning about the constant being too
large for its type).

The UINTx_C macros usually need compiler magic and the manual says:

"There is no support in GCC to express an integer constant of type
__int128 for targets having long long integer with less then 128 bit
width"
 
S

Seebs

I can't see at a glance whether T is a number, struct, and anything else.
That seemed to be the point of JG's remark. In this case it *does* hide some
information.

I usually consider this a bonus. :)

-s
 
J

Jens Gustedt

Am 01/21/2012 07:00 PM, schrieb Kaz Kylheku:
#define UINT128_C(X) ((uint128_t) (X))

No this wouldn't result in an expression that the preprocessor could
interpret as an integer expression.

Better would be something like

#define UINT128_C(X) (0u+((uint128_t)+(X)))

to ensure that it would even work for preprocessor constants in #if
clauses. (The preprocessor would replace the uint128_t with 0 for the
purpose of evaluation.)

But to support uint128_t needs more than that. You'd have to

- make uintmax_t also that type
- as a consequence have to compute with that width in the preprocessor
- implement all the library support, in particular PRIu128 and stuff
like that for printing

Jens
 
J

James Kuyper

#define UINT128_C(X) ((uint128_t) (X))

7.18.4p3: "Each invocation of one of these macros shall expand to an
integer constant expression suitable for use in #if preprocessing
directives."

In the context of a #if preprocessing directive, uint123_t is a
meaningless identifier that would get converted to a 0 (6.10.1p4),
resulting in a syntax error. That's an example of why the macros
governed by 7.18.4p3 cannot contain casts. I believe that they're
supposed to limit their operations to appending appropriate suffixes
like U, or L, or LL; the only example given in the standard appends ULL.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top