Restricted unsigned integer range would have been better?

A

Ansel

pete said:
I have always found
programming with unsigned integers
to be simple and easy,
so your point of view
is difficult for me to understand.

Mixed-type operations (signed, unsigned) perhaps more complex than
necessary.
 
L

Les Cargill

pete said:
I think I see what you mean.
C is a primative tool.
As is typical of primative tools,
study and practice goes a long way towards efficacy.
Prgrammers who like C,
tend to like the primitiveness of it.

This is modestly silly :) C is still a *high level language*,
and there's very little you cannot do with it.

I have personally replaced a really large pile 'o Java
with a relatively small 'C' program. That wasn't
Java's fault.

Don't say "Buh GUI programming..." I'll agree there;
don't use C for that. Or just don't write GUIs.
Mixed type comparisons, is bad C coding style.

Type conversions must be made explicit.
In the case of the absence of a reason to use a signed type,
my default choice for an integer type to use,
is an unsigned integer type.

That's a way. I do it the other way 'round, but
that's fine. Having the "unsigned" keyword be the exception
adds more information to the source code and otherwise constraining*
signed ints is better than simply declaring everything unsigned.

*as in range checks..
I only once recall encountering a mixed type comparison
in code which I was maintaining.
The mixed type comparison which I encountered,
resulted from the wrong choice being made to use type (int),
where an unsigned type should have been.
The contract that I was working under,
required that the code compile without any warnings
and the compiler that we were using,
emitted a warning for the mixed type comparison,
so I changed the (int) type object to an unsigned type.


Well, there ya go.
 
K

Keith Thompson

Les Cargill said:
pete wrote: [...]
I think I see what you mean.
C is a primative tool.
As is typical of primative tools,
study and practice goes a long way towards efficacy.
Prgrammers who like C,
tend to like the primitiveness of it.

This is modestly silly :) C is still a *high level language*,
and there's very little you cannot do with it.

I wouldn't call C a high level language, but that depends entirely
on how you define the phrase "high level".

It's high level in the sense that C programs specify behavior,
not CPU instructions. Of the languages that are "high level" in
that sense, I'd say that C is just about the lowest-level language
in common use.

[...]
Type conversions must be made explicit.

I presume that's meant as advice, not a language rule.

[...]
 
L

Les Cargill

Keith said:
Les Cargill said:
pete wrote: [...]
I think I see what you mean.
C is a primative tool.
As is typical of primative tools,
study and practice goes a long way towards efficacy.
Prgrammers who like C,
tend to like the primitiveness of it.

This is modestly silly :) C is still a *high level language*,
and there's very little you cannot do with it.

I wouldn't call C a high level language, but that depends entirely
on how you define the phrase "high level".


I really think of what Hosfstadter said in "Godel, Escher, Bach" -
that there is BLOOP ( bounded loops, aka Fortran ) and FLOOP (
free loops, Algol and descendents ) and that there can be proven
to be no higher level language than FLOOP.

Perhaps that's out of context; I dunno. It just stuck with me.

Most "higher level languages" aren't about the languages but
the furniture that comes (free) with the language. granted
some of the furniture is really important...

But that's probably maximally pedantic, and I stopped
really worrying about that sort of thing long ago. For a
given app, a certain language system will be the best choice,
and it's best to go that way.
It's high level in the sense that C programs specify behavior,
not CPU instructions. Of the languages that are "high level" in
that sense, I'd say that C is just about the lowest-level language
in common use.

[...]
Type conversions must be made explicit.

I presume that's meant as advice, not a language rule.

Sorry - yes, it's advice.
 
A

Ansel

Keith Thompson said:
Les Cargill said:
pete wrote: [...]
I think I see what you mean.
C is a primative tool.
As is typical of primative tools,
study and practice goes a long way towards efficacy.
Prgrammers who like C,
tend to like the primitiveness of it.

This is modestly silly :) C is still a *high level language*,
and there's very little you cannot do with it.

I wouldn't call C a high level language, but that depends entirely
on how you define the phrase "high level".

It's high level in the sense that C programs specify behavior,
not CPU instructions. Of the languages that are "high level" in
that sense, I'd say that C is just about the lowest-level language
in common use.

High-level language: any language above assembly languages.
Low-level language: assembly languages and below.

Why? Because the low-level languages are CPU-ish: the elements of
programming are instructions or even lower, op codes. High-level languages
abstract that away, so there is the division line, at least traditionally
(as I learned it anyway and still ascribe to that because it makes good
sense).
 
A

Ansel

pete said:
K&R Introduction says "C is a relatively 'low level' language."

That is true if the set in which it is being compared is comprised of only
high-level languages. Relative to most of that set, C is indeed relatively
low-level. Broaden the scope of the comparison set by throwing assembly
language into it and then C is clearly high-level. The lowest of the high
maybe, but definitely high.
 
K

Keith Thompson

Ansel said:
High-level language: any language above assembly languages.
Low-level language: assembly languages and below.

Those are certainly valid definitions of those terms.

But I don't think they're widely accepted. Most programmers would
probably say that Ada, for example, is a high-level language and C is a
low-level language. That's certainly true in a relative sense; C is a
lower-level language that Ada.

(Substitute your favorite higher-level-than-C language for Ada if you
like.)
Why? Because the low-level languages are CPU-ish: the elements of
programming are instructions or even lower, op codes. High-level languages
abstract that away, so there is the division line, at least traditionally
(as I learned it anyway and still ascribe to that because it makes good
sense).

Yes, there's a very strong dividing line between assembly languages and
non-assembly languages, and C is on the high-level side of that line.
But common usage doesn't necessarily follow that logic.
 
B

BartC

Ansel said:
High-level language: any language above assembly languages.
Low-level language: assembly languages and below.

Why? Because the low-level languages are CPU-ish: the elements of
programming are instructions or even lower, op codes. High-level languages
abstract that away, so there is the division line, at least traditionally
(as I learned it anyway and still ascribe to that because it makes good
sense).

A low-level language would be a specific assembler, a machine oriented
language, or a 'high-level' assembler, which latter might look, deceptively,
like high-level, but they are cruder in their capabilities.

But as a high-level language, C is near the bottom of the range. I would
classify it more from it's data handling:

o Static data types always known at compile-time
o Primitive types based around likely machine types
o Collections (arrays, structs) of types which are always of fixed bounds
known at compile-time
o Always explicit memory management
o Always explicit pointer handling (although some constructions look
implicit)

C, arguably, has dynamic (and perhaps flexible) arrays, but handled
explicitly, and things such as VLAs, which are interesting but not enough to
raise it to the next tier! (Pass a VLA to a function, and you still just
have a bare pointer with no idea what length it is.)

For many people, this is enough: if using C to implement a higher-level
language for example, you don't want C's own capabilities to get in the way.

Syntax is less important: more higher-level syntax can be added to C, but if
it's data-handling is the same, then it's still really at the same level
(but, it wouldn't hurt either...).
 
M

Malcolm McLean

בת×ריך ×™×•× ×©×‘×ª,28 ביולי 2012 00:19:35 UTC+1, מ×ת Keith Thompson:
I wouldn't call C a high level language, but that depends entirely
on how you define the phrase "high level".
A high level language is one which makes it easy to perform complex operations with a minimu of code. Usually this comes at a cost of making it difficult to perform simple operations efficiently, and often the complex operations are only a subset of all programming operations.

For instance R has powerful operations for reading in 2 dimensional data tables, subjecting them to statictical analysis, and displaying the results in graphs. However whilst it's possible to get it to play space invaders, it's very difficult. It's also quite hard to get it do things like 3d Fouriertransforms. But it's relatively easy to code a 3d Fourier transform in C, then provide a R-callable interface to the code.
 
P

Philip Lantz

David said:
Good advice.

For my work, it is more than advice - it is a style rule, and I enforce
it with compiler warnings (-Wconversion -Wsign-conversion in gcc).

Do you really? Would you use casts in situations like these?
1. char c = 'x';
2. int *p = malloc(N * sizeof *p);
3. free(p);
4. printf("%c\n", c);
5. while (*s != '\0')
n = n * 10 + (*s - '0');

I would find them to be undesirable clutter.
 
B

Ben Bacarisse

David Brown said:
On 01/08/2012 05:26, Philip Lantz wrote:

Again, I seldom use printf (though it does happen occasionally, more
often in the snprintf variation). And I use "-Wformat" to check
arguments.

I would not bother casting the result to (void), unless I wanted to
specifically indicate that the function's return value is normally
important but that I was ignoring it at the time.

Philip Lantz might be referring to the implicit char to int default
argument promotion that occurs in the ... argument position of vararg
function calls, but I don't think that would affect matter. It follows
the pattern of implicit conversions that you don't object to.

<snip>
 
B

Ben Bacarisse

I don't understand that. Did you mean "and also unsigned" rather than
"and also not negative"?
You could also write it as "n = ((n << 2) + n) << 1 - '0' + *s", and a
dozen other ways that give the same result.

n = (((n << 2) + n) << 1) - '0' + *s"
But why would you do so?
The parenthesis in the original version are there to make the purpose
of the expression clear - obfuscating it to avoid a couple of
parenthesis is just silly.

It's inevitable: any post about how important parentheses are will be
missing parentheses!
 
B

Ben Bacarisse

pete said:
Ben Bacarisse wrote:

No.
It reminded me of a line from a toy atoi
that I once wrote as an exercise.

Ah! You meant that the parentheses can be removed without causing an
otherwise avoidable overflow, I think. Both versions can overflow, but
the "bad" version (n = n * 10 + *s - '0') can cause a needless overflow.

<snip>
 
P

Philip Lantz

David said:
There are some conversions that are done automatically for which it
doesn't make sense to have them explicit. In particular, promotions
that cannot change the value don't need to be explicit (such as
assigning an uint16_t to a uint32_t variable).


Both the reader and the compiler can see that while this is technically
an integer constant assigned to a char variable, there is no risk of
losing data.

The key point here is that the code should be absolutely clear to the
reader, and the reader's interpretation should match the compiler's
interpretation. Explicit casts are needed if there could be any doubt.


First off, I almost never use malloc. I write software for embedded
systems, mostly fairly small systems, and I haven't needed general
dynamic memory more than a couple of times in 20 years. Occasionally
I'll have a more specialised dynamic memory system, but otherwise almost
everything is static (or on the stack).

I would write that as :

int* p = (int*) malloc(N * sizeof(*p));

I prefer to make casts from void* explicit. It also improves
compatibility with C++, for portability of the code.

Again, there is another hidden cast - N (which is presumably an integer
of some sort) will be promoted to size_t before the multiplication. And
again, I don't see a need to cast it here.


No need to cast that one, unless the pointer type is qualified (volatile
or const) - in which case I /would/ want an explicit cast.


Again, I seldom use printf (though it does happen occasionally, more
often in the snprintf variation). And I use "-Wformat" to check arguments.

I would not bother casting the result to (void), unless I wanted to
specifically indicate that the function's return value is normally
important but that I was ignoring it at the time.


I don't see a need for casting here either, as all the implicit casting
is clear and safe (assuming, of course, that s points to a string of
digits and we already know that they are valid). I might add extra code
to limit the loop or check for overflows, depending on the context.

I would, however, include brackets around the loop contents.


So I would write:

char c = 'x';
int *p = (int*) malloc(N * sizeof(*p));
free(p);
printf("%c\n", c);
while (*s != '\0') {
n = n * 10 + (*s - '0');
}

Of course, you picked examples here where explicit casting adds little,
and even someone as fussy as me would omit them. In my real-world code,
it is not uncommon to see casts between signed or unsigned types, or
types of different sizes, where other programmers would likely omit them.

Thanks for your clarifications. I think we are very nearly in complete
agreement. I did, of course, pick examples where I think it is clear the
casts are pointless, plus the malloc case, where the cast is anathema to
some in this group.

(I almost put brackets around the loop body, just to avoid the
distraction, because I *knew* you would comment on it :), but I left
them out for brevity.)
 
P

Philip Lantz

Ben said:
Philip Lantz might be referring to the implicit char to int default
argument promotion that occurs in the ... argument position of vararg
function calls

I was.
 
M

Malcolm McLean

בת×ריך ×™×•× ×©×‘×ª,28 ביולי 2012 05:35:49 UTC+1, מ×ת Ansel:
That is true if the set in which it is being compared is comprised of only
high-level languages. Relative to most of that set, C is indeed relatively
low-level. Broaden the scope of the comparison set by throwing assembly
language into it and then C is clearly high-level. The lowest of the high
maybe, but definitely high.
Really the answer depends on your librsries. C without a library isn't muchhigher-level than assembly language. It's portable, it has support for floating point, structuers, strings, and pointer management, and it does your subroutine bookkeeping for you. But that's only a thin layer on top of assembler.

C with a library can have all sorts of sophisticated capabilites. The thin layer on top of assembler is an important thin layer, because it enables you to string together library calls very easily.
 
K

Keith Thompson

Malcolm McLean said:
Really the answer depends on your librsries. C without a library isn't
much higher-level than assembly language. It's portable, it has
support for floating point, structuers, strings, and pointer
management, and it does your subroutine bookkeeping for you. But
that's only a thin layer on top of assembler.
[...]

I don't consider it a thin layer. The big difference is that assembly
language programs specify CPU instructions, while C programs specify
behavior.

(And Malcolm, can you please find a way to keep your lines down to 72
columns or so? If you're posting through Google Groups, you can always
copy-and-paste your article to a text editor and back before posting.)
 
A

Ansel

Malcolm said:
?????? ??? ???, 28 ????? 2012 05:35:49 UTC+1, ??? Ansel:
Really the answer depends on your librsries.

Not by my defintions. Your theory rejected.
 
A

Ansel

Keith said:
Malcolm McLean said:
Really the answer depends on your librsries. C without a library
isn't much higher-level than assembly language. It's portable, it has
support for floating point, structuers, strings, and pointer
management, and it does your subroutine bookkeeping for you. But
that's only a thin layer on top of assembler.
[...]

I don't consider it a thin layer. The big difference is that assembly
language programs specify CPU instructions, while C programs specify
behavior.

That is a lame post. "behavior"? Assembly instructions do not cause
behavior? What was wrong with my definition that had in it that C abstracts
the CPU instructions?
 

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

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top