Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.c > #169256 > unrolled thread
| Started by | scs@eskimo.com (Steve Summit) |
|---|---|
| First post | 2023-02-13 15:18 +0000 |
| Last post | 2023-02-15 05:31 -0800 |
| Articles | 20 on this page of 25 — 14 participants |
Back to article view | Back to comp.lang.c
FAQ list update: Q1.1: choosing types scs@eskimo.com (Steve Summit) - 2023-02-13 15:18 +0000
Re: FAQ list update: Q1.1: choosing types Anton Shepelev <anton.txt@g{oogle}mail.com> - 2023-02-13 18:27 +0300
Re: FAQ list update: Q1.1: choosing types scott@slp53.sl.home (Scott Lurndal) - 2023-02-13 16:27 +0000
Re: FAQ list update: Q1.1: choosing types Oğuz <oguzismailuysal@gmail.com> - 2023-02-14 08:55 +0300
Re: FAQ list update: Q1.1: choosing types Lew Pitcher <lew.pitcher@digitalfreehold.ca> - 2023-02-13 18:07 +0000
Re: FAQ list update: Q1.1: choosing types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-02-13 10:48 -0800
Re: FAQ list update: Q1.1: choosing types Kaz Kylheku <864-117-4973@kylheku.com> - 2023-02-14 03:10 +0000
Re: FAQ list update: Q1.1: choosing types Blue-Maned_Hawk <bluemanedhawk@gmail.com> - 2023-02-14 17:33 -0500
Re: FAQ list update: Q1.1: choosing types Öö Tiib <ootiib@hot.ee> - 2023-02-13 23:24 -0800
Re: FAQ list update: Q1.1: choosing types bart c <bart4858@gmail.com> - 2023-02-14 06:22 -0800
Re: FAQ list update: Q1.1: choosing types Blue-Maned_Hawk <bluemanedhawk@gmail.com> - 2023-02-14 17:48 -0500
Re: FAQ list update: Q1.1: choosing types John Dill <jadill33@gmail.com> - 2023-02-14 08:17 -0800
Re: FAQ list update: Q1.1: choosing types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-02-14 12:34 -0800
Re: FAQ list update: Q1.1: choosing types John Dill <jadill33@gmail.com> - 2023-02-15 10:04 -0800
Re: FAQ list update: Q1.1: choosing types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-02-15 10:28 -0800
Re: FAQ list update: Q1.1: choosing types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-02-15 10:57 -0800
Re: FAQ list update: Q1.1: choosing types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-02-15 11:17 -0800
Re: FAQ list update: Q1.1: choosing types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-02-15 11:32 -0800
Re: FAQ list update: Q1.1: choosing types John Dill <jadill33@gmail.com> - 2023-02-15 11:01 -0800
Re: FAQ list update: Q1.1: choosing types Keith Thompson <Keith.S.Thompson+u@gmail.com> - 2023-02-15 11:28 -0800
Re: FAQ list update: Q1.1: choosing types John Dill <jadill33@gmail.com> - 2023-02-15 14:00 -0800
Re: FAQ list update: Q1.1: choosing types Tim Rentsch <tr.17687@z991.linuxsc.com> - 2023-02-15 02:54 -0800
Re: FAQ list update: Q1.1: choosing types Anton Shepelev <anton.txt@g{oogle}mail.com> - 2023-02-15 14:43 +0300
Re: FAQ list update: Q1.1: choosing types David Brown <david.brown@hesbynett.no> - 2023-02-15 13:55 +0100
Re: FAQ list update: Q1.1: choosing types Malcolm McLean <malcolm.arthur.mclean@gmail.com> - 2023-02-15 05:31 -0800
Page 1 of 2 [1] 2 Next page →
| From | scs@eskimo.com (Steve Summit) |
|---|---|
| Date | 2023-02-13 15:18 +0000 |
| Subject | FAQ list update: Q1.1: choosing types |
| Message-ID | <2023Feb13.1015.scs.0001@quinine2.local> |
In its very first question, the FAQ list currently says: If you might need large values (above 32,767 or below -32,767), use long. Otherwise, if space is very important (i.e. if there are large arrays or many structures), use short. Otherwise, use int. If well-defined overflow characteristics are important and negative values are not, or if you want to steer clear of sign-extension problems when manipulating bits or bytes, use one of the corresponding unsigned types. (Beware when mixing signed and unsigned values in expressions, though; see question 3.19.) Although character types (especially unsigned char) can be used as ``tiny'' integers, doing so is sometimes more trouble than it's worth. The compiler will have to emit extra code to convert between char and int (making the executable larger), and unexpected sign extension can be troublesome. (Using unsigned char can help; see question 12.1 for a related problem.) A similar space/time tradeoff applies when deciding between float and double. (Many compilers still convert all float values to double during expression evaluation.) ...If for some reason you need to declare something with an exact size (usually the only good reason for doing so is when attempting to conform to some externally-imposed storage layout, but see question 20.5), be sure to encapsulate the choice behind an appropriate typedef, but see question 1.3. Besides cleaning up the wording (this answer, like much of my writing, is afflicted with Too Many Parentheticals :-) ), I am strongly considering making one or two additional, potentially controversial points: If you want to make the considered assumption that your code will only ever run on "modern" hardware, you can say that plain int can hold up to +-2147483647 (that is, has 32 bits). Some coding guidelines, notably MISRA, deprecate the "abstract" types short, int, and long, and mandate always using exact-size types like int16_t and int32_t. To the first point, believe me, I do know what the Standard guarantees about type int, and I remember well the pejorative phrase "All the world's a VAX" as promulgated in, among other things, Henry Spencer's 10 Commandments. But I also know that the codebase I work on every day in my day job makes this assumption, and I'm pretty sure I'm not alone. To the second point, while I personally disagree up, down, and sideways with the dictum "don't use plain int", I can't ignore the fact that many practicing C programmers do advocate and follow it, and many projects faithfully honor MISRA. Opinions (in support or denigration of either point) welcome. Steve Summit scs@eskimo.com
[toc] | [next] | [standalone]
| From | Anton Shepelev <anton.txt@g{oogle}mail.com> |
|---|---|
| Date | 2023-02-13 18:27 +0300 |
| Message-ID | <20230213182737.cf2e68f94204d62270fbe304@g{oogle}mail.com> |
| In reply to | #169256 |
Steve Summit: > To the first point, believe me, I do know what the > Standard guarantees about type int, and I remember well > the pejorative phrase "All the world's a VAX" as > promulgated in, among other things, Henry Spencer's 10 > Commandments. But I also know that the codebase I work on > every day in my day job makes this assumption, and I'm > pretty sure I'm not alone. > [...] > Opinions (in support or denigration of either point) > welcome. I have a philosophical consideration with pracitcal implications: the closer you adhere to the ideal standard C, the more future-proof and maintainance-free the FAQ becomes. That said, one apprach would be to write about the standard C in vacuum, without regard to (currently) modern compilers, practices, and assumptions, which fall under the volatile subject of "Practical C" rather than the more stable and fundamental "C in itself." -- () ascii ribbon campaign -- against html e-mail /\ www.asciiribbon.org -- against proprietary attachments
[toc] | [prev] | [next] | [standalone]
| From | scott@slp53.sl.home (Scott Lurndal) |
|---|---|
| Date | 2023-02-13 16:27 +0000 |
| Message-ID | <uxtGL.613679$8_id.534973@fx09.iad> |
| In reply to | #169256 |
scs@eskimo.com (Steve Summit) writes: >In its very first question, the FAQ list currently says: > > If you might need large values (above 32,767 or > below -32,767), use long. Otherwise, if space is > very important (i.e. if there are large arrays or > many structures), use short. Otherwise, use int. > If well-defined overflow characteristics are important > and negative values are not, or if you want to steer > clear of sign-extension problems when manipulating bits > or bytes, use one of the corresponding unsigned types. > (Beware when mixing signed and unsigned values in > expressions, though; see question 3.19.) > > Although character types (especially unsigned char) can > be used as ``tiny'' integers, doing so is sometimes more > trouble than it's worth. The compiler will have to emit > extra code to convert between char and int (making the > executable larger), and unexpected sign extension can be > troublesome. (Using unsigned char can help; see question > 12.1 for a related problem.) > > A similar space/time tradeoff applies when deciding > between float and double. (Many compilers still convert > all float values to double during expression evaluation.) > > ...If for some reason you need to declare something with > an exact size (usually the only good reason for doing so > is when attempting to conform to some externally-imposed > storage layout, but see question 20.5), be sure to > encapsulate the choice behind an appropriate typedef, > but see question 1.3. > >Besides cleaning up the wording (this answer, like much of my >writing, is afflicted with Too Many Parentheticals :-) ), I am That description is way out of date. The idea that extending from a byte to a word causes the executable to be larger is misleading at best, particularly given that byte-width loads will extend (sign or zero) the value to the target register in most cases automatically with no additional code required.
[toc] | [prev] | [next] | [standalone]
| From | Oğuz <oguzismailuysal@gmail.com> |
|---|---|
| Date | 2023-02-14 08:55 +0300 |
| Message-ID | <tsf7oh$2e9n2$1@dont-email.me> |
| In reply to | #169259 |
On 2/13/23 7:27 PM, Scott Lurndal wrote: > byte-width loads > will extend (sign or zero) the value to the target register > in most cases automatically with no additional code required. Can you provide an example where this happens? One of my toy programs spend too much time on a `movsbl' instruction (the C code is `(c & 0xC0) != 0x80', `c' is a char) and I wonder if I can eliminate it somehow.
[toc] | [prev] | [next] | [standalone]
| From | Lew Pitcher <lew.pitcher@digitalfreehold.ca> |
|---|---|
| Date | 2023-02-13 18:07 +0000 |
| Message-ID | <tsdu94$272pu$1@dont-email.me> |
| In reply to | #169256 |
On Mon, 13 Feb 2023 15:18:49 +0000, Steve Summit wrote: > In its very first question, the FAQ list currently says: > > If you might need large values (above 32,767 or below -32,767), use > long. Otherwise, if space is very important (i.e. if there are large > arrays or many structures), use short. Otherwise, use int. > If well-defined overflow characteristics are important and negative > values are not, or if you want to steer clear of sign-extension > problems when manipulating bits or bytes, use one of the corresponding > unsigned types. (Beware when mixing signed and unsigned values in > expressions, though; see question 3.19.) > > Although character types (especially unsigned char) can be used as > ``tiny'' integers, doing so is sometimes more trouble than it's worth. > The compiler will have to emit extra code to convert between char and > int (making the executable larger), and unexpected sign extension can > be troublesome. (Using unsigned char can help; see question 12.1 for a > related problem.) > > A similar space/time tradeoff applies when deciding between float and > double. (Many compilers still convert all float values to double > during expression evaluation.) > > ...If for some reason you need to declare something with an exact size > (usually the only good reason for doing so is when attempting to > conform to some externally-imposed storage layout, but see question > 20.5), be sure to encapsulate the choice behind an appropriate typedef, > but see question 1.3. > > Besides cleaning up the wording (this answer, like much of my writing, > is afflicted with Too Many Parentheticals :-) ), I am strongly > considering making one or two additional, potentially controversial > points: > > If you want to make the considered assumption that your code will only > ever run on "modern" hardware, you can say that plain int can hold up > to +-2147483647 (that is, has 32 bits). > > Some coding guidelines, notably MISRA, deprecate the "abstract" types > short, int, and long, and mandate always using exact-size types like > int16_t and int32_t. > > To the first point, believe me, I do know what the Standard guarantees > about type int, and I remember well the pejorative phrase "All the > world's a VAX" as promulgated in, among other things, Henry Spencer's 10 > Commandments. But I also know that the codebase I work on every day in > my day job makes this assumption, and I'm pretty sure I'm not alone. > > To the second point, while I personally disagree up, down, and sideways > with the dictum "don't use plain int", I can't ignore the fact that many > practicing C programmers do advocate and follow it, > and many projects faithfully honor MISRA. > > Opinions (in support or denigration of either point) welcome. For clarification, the FAQ question in question reads "How should I decide which integer type to use?" Having programmed professionally for 30 years, my answer would differ greatly from the FAQ answer as published. As the "C Language" implementation ecosystem varies in range from microcontrollers that can barely muster 65536 bytes of memory and native 16bit integer math, to systems that support gigabytes (if not terabytes) of memory and native 64bit integer math, and a range of compiler-hosted low-level optimization tools that range from none to over the top, I'd have to say that an answer that concentrates on the machine-level implications of "integer type" choices misses the mark. I would be tempted to answer the question by first saying that the programmer should determine the range of values that the code will require the integer to hold, then select the closest "integer type" that meets (or exceeds) this range. That integer type /might/ be "short" (for instance, in a compiler that natively generates 64bit integers), or "long" (for instance, in a compiler that natively generates 16bit integers), or something else. /If/ the code may be compiled for different platforms, or with compilers of different limits, use the "portable" integer type (int32_t, uint64_t, etc) that meets (or exceeds) the variable's range. Once you've made this decision, be prepared to modify it based on performance testing and modelling. -- Lew Pitcher "In Skills We Trust"
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-02-13 10:48 -0800 |
| Message-ID | <f018f931-df84-46a5-822f-51497f4caaecn@googlegroups.com> |
| In reply to | #169256 |
On Monday, 13 February 2023 at 15:19:04 UTC, Steve Summit wrote: > In its very first question, the FAQ list currently says: > > If you might need large values (above 32,767 or > below -32,767), use long. Otherwise, if space is > very important (i.e. if there are large arrays or > many structures), use short. Otherwise, use int. > If well-defined overflow characteristics are important > and negative values are not, or if you want to steer > clear of sign-extension problems when manipulating bits > or bytes, use one of the corresponding unsigned types. > (Beware when mixing signed and unsigned values in > expressions, though; see question 3.19.) > > Although character types (especially unsigned char) can > be used as ``tiny'' integers, doing so is sometimes more > trouble than it's worth. The compiler will have to emit > extra code to convert between char and int (making the > executable larger), and unexpected sign extension can be > troublesome. (Using unsigned char can help; see question > 12.1 for a related problem.) > > A similar space/time tradeoff applies when deciding > between float and double. (Many compilers still convert > all float values to double during expression evaluation.) > > ...If for some reason you need to declare something with > an exact size (usually the only good reason for doing so > is when attempting to conform to some externally-imposed > storage layout, but see question 20.5), be sure to > encapsulate the choice behind an appropriate typedef, > but see question 1.3. > > Besides cleaning up the wording (this answer, like much of my > writing, is afflicted with Too Many Parentheticals :-) ), I am > strongly considering making one or two additional, potentially > controversial points: > > If you want to make the considered assumption that your > code will only ever run on "modern" hardware, you can say > that plain int can hold up to +-2147483647 (that is, has > 32 bits). > > Some coding guidelines, notably MISRA, deprecate the > "abstract" types short, int, and long, and mandate always > using exact-size types like int16_t and int32_t. > > To the first point, believe me, I do know what the Standard > guarantees about type int, and I remember well the pejorative > phrase "All the world's a VAX" as promulgated in, among other > things, Henry Spencer's 10 Commandments. But I also know that > the codebase I work on every day in my day job makes this > assumption, and I'm pretty sure I'm not alone. > > To the second point, while I personally disagree up, down, and > sideways with the dictum "don't use plain int", I can't ignore the > fact that many practicing C programmers do advocate and follow it, > and many projects faithfully honor MISRA. > > Opinions (in support or denigration of either point) welcome. > As a general rule data is real, though of course quantised for measuring and representation reasons, whilst the integers in the program represent either counts of data elements, or indices into arrays of data. That's only a general rule, of course, and it's possible to devise a program which works mainly on discrete data. size_t was designed to hold a size in bytes of memory. But it quickly became extended to holding a count of obhjects in memory. Which means that an index needs to be a size_t. Which means that if you are consistent, then almost all the integers in the program will be size_ts. However few people are consistent. People don't like using a type named "size_t" to hold something which isn't a size. And intermediate index values can go negative, for example when applying a windowed filter to an array. And, because size_t can hold the szie of any object, it has to be wide enough to hold the largest object the system can create, which typically means it needs to be 64 bits. This wastes memory and, more importantly, cache. However there's no agreement about how to solve this problem. Instead the committee has introduced more standard integer types. Which is asking for problems when types resolve to the same underlying machine instructions on the test architecture, and different underlying machine instructions on the deployment architecture.
[toc] | [prev] | [next] | [standalone]
| From | Kaz Kylheku <864-117-4973@kylheku.com> |
|---|---|
| Date | 2023-02-14 03:10 +0000 |
| Message-ID | <20230213190727.848@kylheku.com> |
| In reply to | #169256 |
On 2023-02-13, Steve Summit <scs@eskimo.com> wrote: > Some coding guidelines, notably MISRA, deprecate the > "abstract" types short, int, and long, and mandate always > using exact-size types like int16_t and int32_t. In that MISRAble industry, it's acceptable for mechanically sound automobiles to be scrapped due to software obsolescence. -- TXR Programming Language: http://nongnu.org/txr Cygnal: Cygwin Native Application Library: http://kylheku.com/cygnal Mastodon: @Kazinator@mstdn.ca
[toc] | [prev] | [next] | [standalone]
| From | Blue-Maned_Hawk <bluemanedhawk@gmail.com> |
|---|---|
| Date | 2023-02-14 17:33 -0500 |
| Message-ID | <tsh275$2l2ps$3@bluemanedhawk.eternal-september.org> |
| In reply to | #169264 |
On 2/13/23 22:10, Kaz Kylheku wrote: > On 2023-02-13, Steve Summit <scs@eskimo.com> wrote: >> Some coding guidelines, notably MISRA, deprecate the >> "abstract" types short, int, and long, and mandate always >> using exact-size types like int16_t and int32_t. > > In that MISRAble industry, it's acceptable for mechanically sound > automobiles to be scrapped due to software obsolescence. > Does that bear any direct relation to the exact-width type requirements? -- ⚗︎ | /blu.mɛin.dʰak/ | shortens to "Hawk" | he/him/his/himself/Mr. bluemanedhawk.github.io Bitches stole my whole ass ␔🭖᷿᪳𝼗᷍⏧𒒫𐻾ࣛ↉�⃣ quoted-printable, can't have shit in Thunderbird 😩
[toc] | [prev] | [next] | [standalone]
| From | Öö Tiib <ootiib@hot.ee> |
|---|---|
| Date | 2023-02-13 23:24 -0800 |
| Message-ID | <5281302c-69cb-447f-890f-a8bf31882d5fn@googlegroups.com> |
| In reply to | #169256 |
On Monday, 13 February 2023 at 17:19:04 UTC+2, Steve Summit wrote: > In its very first question, the FAQ list currently says: > > If you might need large values (above 32,767 or > below -32,767), use long. Otherwise, if space is > very important (i.e. if there are large arrays or > many structures), use short. Otherwise, use int. > If well-defined overflow characteristics are important > and negative values are not, or if you want to steer > clear of sign-extension problems when manipulating bits > or bytes, use one of the corresponding unsigned types. > (Beware when mixing signed and unsigned values in > expressions, though; see question 3.19.) > > Although character types (especially unsigned char) can > be used as ``tiny'' integers, doing so is sometimes more > trouble than it's worth. The compiler will have to emit > extra code to convert between char and int (making the > executable larger), and unexpected sign extension can be > troublesome. (Using unsigned char can help; see question > 12.1 for a related problem.) > > A similar space/time tradeoff applies when deciding > between float and double. (Many compilers still convert > all float values to double during expression evaluation.) > > ...If for some reason you need to declare something with > an exact size (usually the only good reason for doing so > is when attempting to conform to some externally-imposed > storage layout, but see question 20.5), be sure to > encapsulate the choice behind an appropriate typedef, > but see question 1.3. > > Besides cleaning up the wording (this answer, like much of my > writing, is afflicted with Too Many Parentheticals :-) ), I am > strongly considering making one or two additional, potentially > controversial points: > > If you want to make the considered assumption that your > code will only ever run on "modern" hardware, you can say > that plain int can hold up to +-2147483647 (that is, has > 32 bits). > > Some coding guidelines, notably MISRA, deprecate the > "abstract" types short, int, and long, and mandate always > using exact-size types like int16_t and int32_t. > > To the first point, believe me, I do know what the Standard > guarantees about type int, and I remember well the pejorative > phrase "All the world's a VAX" as promulgated in, among other > things, Henry Spencer's 10 Commandments. But I also know that > the codebase I work on every day in my day job makes this > assumption, and I'm pretty sure I'm not alone. > > To the second point, while I personally disagree up, down, and > sideways with the dictum "don't use plain int", I can't ignore the > fact that many practicing C programmers do advocate and follow it, > and many projects faithfully honor MISRA. > > Opinions (in support or denigration of either point) welcome. > The reason of those coding guidelines is that world is more inter-connected and also individual devices consist of bigger number of subsystems. Exact size is needed for communicating; code with exact size types simplifies replacing subsystems.
[toc] | [prev] | [next] | [standalone]
| From | bart c <bart4858@gmail.com> |
|---|---|
| Date | 2023-02-14 06:22 -0800 |
| Message-ID | <2e1d44fe-bd17-47ea-b4c9-90a541af1febn@googlegroups.com> |
| In reply to | #169256 |
On Monday, 13 February 2023 at 15:19:04 UTC, Steve Summit wrote:
> In its very first question, the FAQ list currently says:
>
>" If you might need large values (above 32,767 or
> below -32,767), use long."
> Besides cleaning up the wording (this answer, like much of my
> writing, is afflicted with Too Many Parentheticals :-) ), I am
> strongly considering making one or two additional, potentially
> controversial points:
>
> If you want to make the considered assumption that your
> code will only ever run on "modern" hardware, you can say
> that plain int can hold up to +-2147483647 (that is, has
> 32 bits).
That description /is/ dated, and yet C does say that `int` is only guaranteed to be 16 bits.
But if you leave it, it will be suggested that everybody uses 'long' instead, which has its own problems, like varying in size between 32-bit and 64-bit Linux, so you might end up with a 64-bit value, when the requirement was no more than 32 bits.
> Some coding guidelines, notably MISRA, deprecate the
> "abstract" types short, int, and long, and mandate always
> using exact-size types like int16_t and int32_t.
Which have yet more problems of their own, since the rest of the languge doesn't recogniss those as native types; you still use:
printf("%ld",a);
123LL
123 Has a maximum value of INT_MAX, whatever int happens to be
I don't have any suggestions; you will have your work cut out. I've long thought C's type system is messy, and wouldn't relish documenting it, let alone offer advice given the vast range of hardware the language can be used on.
> To the first point, believe me, I do know what the Standard
> guarantees about type int, and I remember well the pejorative
> phrase "All the world's a VAX" as promulgated in, among other
> things, Henry Spencer's 10 Commandments. But I also know that
> the codebase I work on every day in my day job makes this
> assumption, and I'm pretty sure I'm not alone.
>
> To the second point, while I personally disagree up, down, and
> sideways with the dictum "don't use plain int", I can't ignore the
> fact that many practicing C programmers do advocate and follow it,
Plain int was a "don't care" type. It could be assumed to be sufficiently wide enough to match the scale of machine. But for a long time it has actually been too small for that purpose.
I normally use my languages where default 'int' has been 64-bits for a decade. That really is "don't care", as it can accommodate most things: RAM capacity, array sizes, disk capacity, file sizes...
But a huge amount of C code still uses plain 'int', and most implementations, outside of microcontrollers, have it as 32-bits, even though the dominant hardware is 64-bit. Care needs to be taken, and signed overflow is distinct possibility.
[toc] | [prev] | [next] | [standalone]
| From | Blue-Maned_Hawk <bluemanedhawk@gmail.com> |
|---|---|
| Date | 2023-02-14 17:48 -0500 |
| Message-ID | <tsh333$2l2pt$1@bluemanedhawk.eternal-september.org> |
| In reply to | #169267 |
On 2/14/23 09:22, bart c wrote:
> On Monday, 13 February 2023 at 15:19:04 UTC, Steve Summit wrote:
>
> [snip]
>
>> Some coding guidelines, notably MISRA, deprecate the
>> "abstract" types short, int, and long, and mandate always
>> using exact-size types like int16_t and int32_t.
>
> Which have yet more problems of their own, since the rest of the languge doesn't recogniss those as native types; you still use:
>
> printf("%ld",a);
> > [snip]
For that particular discrepancy, the <inttypes.h> header has macros
that expand to strings literals which correspond to the appropriate
specifier sequence, and C23 will introduce the `%w𝑁` and `%wf𝑁` length
modifiers. Strangely, the latter isn't required to work with arbitrary
`_BitInt()` types, despite C23 introducing those as well.
--
⚗︎ | /blu.mɛin.dʰak/ | shortens to "Hawk" | he/him/his/himself/Mr.
bluemanedhawk.github.io
Bitches stole my whole ass ␔🭖᷿᪳𝼗᷍⏧𒒫𐻾ࣛ↉�⃣ quoted-printable, can't
have shit in Thunderbird 😩
[toc] | [prev] | [next] | [standalone]
| From | John Dill <jadill33@gmail.com> |
|---|---|
| Date | 2023-02-14 08:17 -0800 |
| Message-ID | <a4d79dc0-db6d-4a94-9a52-fb603d75f1ccn@googlegroups.com> |
| In reply to | #169256 |
On Monday, February 13, 2023 at 10:19:04 AM UTC-5, Steve Summit wrote:
> In its very first question, the FAQ list currently says:
>
> If you might need large values (above 32,767 or
> below -32,767), use long. Otherwise, if space is
> very important (i.e. if there are large arrays or
> many structures), use short. Otherwise, use int.
> If well-defined overflow characteristics are important
> and negative values are not, or if you want to steer
> clear of sign-extension problems when manipulating bits
> or bytes, use one of the corresponding unsigned types.
> (Beware when mixing signed and unsigned values in
> expressions, though; see question 3.19.)
>
> Although character types (especially unsigned char) can
> be used as ``tiny'' integers, doing so is sometimes more
> trouble than it's worth. The compiler will have to emit
> extra code to convert between char and int (making the
> executable larger), and unexpected sign extension can be
> troublesome. (Using unsigned char can help; see question
> 12.1 for a related problem.)
>
> A similar space/time tradeoff applies when deciding
> between float and double. (Many compilers still convert
> all float values to double during expression evaluation.)
>
> ...If for some reason you need to declare something with
> an exact size (usually the only good reason for doing so
> is when attempting to conform to some externally-imposed
> storage layout, but see question 20.5), be sure to
> encapsulate the choice behind an appropriate typedef,
> but see question 1.3.
>
> Besides cleaning up the wording (this answer, like much of my
> writing, is afflicted with Too Many Parentheticals :-) ), I am
> strongly considering making one or two additional, potentially
> controversial points:
>
> If you want to make the considered assumption that your
> code will only ever run on "modern" hardware, you can say
> that plain int can hold up to +-2147483647 (that is, has
> 32 bits).
>
> Some coding guidelines, notably MISRA, deprecate the
> "abstract" types short, int, and long, and mandate always
> using exact-size types like int16_t and int32_t.
>
> To the first point, believe me, I do know what the Standard
> guarantees about type int, and I remember well the pejorative
> phrase "All the world's a VAX" as promulgated in, among other
> things, Henry Spencer's 10 Commandments. But I also know that
> the codebase I work on every day in my day job makes this
> assumption, and I'm pretty sure I'm not alone.
>
> To the second point, while I personally disagree up, down, and
> sideways with the dictum "don't use plain int", I can't ignore the
> fact that many practicing C programmers do advocate and follow it,
> and many projects faithfully honor MISRA.
>
> Opinions (in support or denigration of either point) welcome.
I'll chime in to provide one sample programmer to your pool. I work
in avionics with a combination of largely Ada and C.
I tend to use int when there is an apriori established pattern of usage
in the standard library, with the most common examples of using 'int'
are as a return value, e.g.
int date_compare( struct date d1, struct date d2 );
or as a generic character, e.g. 'fputc'.
Usage of int as a general storage class is rare in my area of development
which focuses on unambiguous sizes for storage. This is required for
defining interfaces of communication using either files or network
structured records. However, 'int' may be used as a signed count whose
physical storage size is likely to be unimportant, e.g.
struct c_greg_date c_date_add_weeks( struct c_greg_date date, int weeks );
I fall into the size_t camp (instead of 'int') for common looping of unsigned
sequences. For size_t values where a -1 is needed for semantics, we use
a preprocessor sequence to generate a signed version of size_t called
ssize_t.
I prefer 'bool' over 'int' for boolean constructs in APIs.
I heavily typedef integer types for implicitly attributing additional semantics
to the integer storage type. I heavily use constraint checking in APIs to
validate integer ranges (and parameters in general). Here's a example of
the style (this function just happened to have a lot of constraint checking).
\code
struct c_greg_date c_partial_date( c_greg_year year,
c_greg_month month,
c_greg_day day )
{
struct c_greg_date date;
c_return_value_if_fail( year >= 0, gc_invalid_greg_date );
c_return_value_if_fail( month >= 0 && month <= C_DECEMBER, gc_invalid_greg_date );
if ( year != 0 && month != 0 ) {
c_return_value_if_fail( day >= 0 && day <= c_days_in_month( month, year ), gc_invalid_greg_date );
} else {
c_return_value_if_fail( day >= 0 && day <= 31, gc_invalid_greg_date );
}
date.year = year;
date.month = month;
date.day = day;
return date;
}
\endcode
The macro c_return_value_if_fail can be configured to print or log a
diagnostic when enabled, showing when constraints are broken.
I'm heavily tainted by working with Ada for almost a decade, so keep that
in mind.
Best regards,
John D.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-02-14 12:34 -0800 |
| Message-ID | <87ttzoq943.fsf@nosuchdomain.example.com> |
| In reply to | #169268 |
John Dill <jadill33@gmail.com> writes:
[...]
> I fall into the size_t camp (instead of 'int') for common looping of unsigned
> sequences. For size_t values where a -1 is needed for semantics, we use
> a preprocessor sequence to generate a signed version of size_t called
> ssize_t.
[...]
POSIX defines a type ssize_t, a signed type that may or may not be the
signed type corresponding to size_t. It's defined in <sys/types.h> and
other headers. If there's any chance of your code being compiled under
POSIX, you might consider checking whether SSIZE_T is defined, and if so
just use the POSIX ssize_t (and be aware that it might not be the signed
type corresponding to size_t). Or pick a different name for your type.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | John Dill <jadill33@gmail.com> |
|---|---|
| Date | 2023-02-15 10:04 -0800 |
| Message-ID | <fb2a9938-72f1-438b-95de-ca580431f1e3n@googlegroups.com> |
| In reply to | #169269 |
On Tuesday, February 14, 2023 at 3:34:52 PM UTC-5, Keith Thompson wrote:
> John Dill <jadi...@gmail.com> writes:
> [...]
> > I fall into the size_t camp (instead of 'int') for common looping of unsigned
> > sequences. For size_t values where a -1 is needed for semantics, we use
> > a preprocessor sequence to generate a signed version of size_t called
> > ssize_t.
> [...]
>
> POSIX defines a type ssize_t, a signed type that may or may not be the
> signed type corresponding to size_t. It's defined in <sys/types.h> and
> other headers. If there's any chance of your code being compiled under
> POSIX, you might consider checking whether SSIZE_T is defined, and if so
> just use the POSIX ssize_t (and be aware that it might not be the signed
> type corresponding to size_t). Or pick a different name for your type.
Agreed. We have something along these lines, with the build system
handling the definitions of the HAVE tests.
We lean on POSIX whenever possible, but not all environments support
POSIX.
\code
/* If the <sys/types.h> header file is found, including the file
should define the 'ssize_t' type. */
#if defined(HAVE_SYS_TYPES_H)
# include <sys/types.h>
#else
# if !defined(HAVE_SSIZE_T)
/*
* The best candidate to define 'ssize_t' is 'ptrdiff_t'. If
* 'ptrdiff_t' is not found, then the fallback type will be
* 'long int'.
*/
# if defined(PTRDIFF_MAX)
typedef ptrdiff_t ssize_t;
# else
typedef long int ssize_t;
# endif
# endif
#endif
C_STATIC_ASSERT (sizeof (ssize_t) == sizeof (size_t),
ssize_t_is_compatible_with_size_t);
\endcode
Best regards,
John D.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-02-15 10:28 -0800 |
| Message-ID | <87pmaarden.fsf@nosuchdomain.example.com> |
| In reply to | #169277 |
John Dill <jadill33@gmail.com> writes:
> On Tuesday, February 14, 2023 at 3:34:52 PM UTC-5, Keith Thompson wrote:
>> John Dill <jadi...@gmail.com> writes:
>> [...]
>> > I fall into the size_t camp (instead of 'int') for common looping of unsigned
>> > sequences. For size_t values where a -1 is needed for semantics, we use
>> > a preprocessor sequence to generate a signed version of size_t called
>> > ssize_t.
>> [...]
>>
>> POSIX defines a type ssize_t, a signed type that may or may not be the
>> signed type corresponding to size_t. It's defined in <sys/types.h> and
>> other headers. If there's any chance of your code being compiled under
>> POSIX, you might consider checking whether SSIZE_T is defined, and if so
>> just use the POSIX ssize_t (and be aware that it might not be the signed
>> type corresponding to size_t). Or pick a different name for your type.
>
> Agreed. We have something along these lines, with the build system
> handling the definitions of the HAVE tests.
>
> We lean on POSIX whenever possible, but not all environments support
> POSIX.
>
> \code
> /* If the <sys/types.h> header file is found, including the file
> should define the 'ssize_t' type. */
> #if defined(HAVE_SYS_TYPES_H)
> # include <sys/types.h>
> #else
> # if !defined(HAVE_SSIZE_T)
> /*
> * The best candidate to define 'ssize_t' is 'ptrdiff_t'. If
> * 'ptrdiff_t' is not found, then the fallback type will be
> * 'long int'.
> */
> # if defined(PTRDIFF_MAX)
> typedef ptrdiff_t ssize_t;
> # else
> typedef long int ssize_t;
> # endif
> # endif
> #endif
> C_STATIC_ASSERT (sizeof (ssize_t) == sizeof (size_t),
> ssize_t_is_compatible_with_size_t);
> \endcode
Rather than HAVE_SSIZE_T, you could check whether SSIZE_MAX is
defined in <limits.h>.
ptrdiff_t has been standard since C89/C90. You can probably
get away with not testing for it. Note that PTRDIFF_MAX wasn't
introduced until C99, so you could get a false negative on some
old implementations.
An alternative might be to check the values of UINT_MAX, ULONG_MAX,
and ULLONG_MAX vs. SIZE_MAX and use the corresponding signed type
int, long, or long long. That's if you want to be really picky,
but what you have should work on any realistic target platform.
The name "ssize_t_is_compatible_with_size_t" is a bit misleading.
C type compatibility is defined very narrowly. A signed type is
never *compatible* with an unsigned type. What is "compatible"
supposed to mean in this context?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Malcolm McLean <malcolm.arthur.mclean@gmail.com> |
|---|---|
| Date | 2023-02-15 10:57 -0800 |
| Message-ID | <4803956e-d074-4787-b063-ed0593ca949cn@googlegroups.com> |
| In reply to | #169278 |
On Wednesday, 15 February 2023 at 18:29:07 UTC, Keith Thompson wrote: > John Dill <jadi...@gmail.com> writes: > > On Tuesday, February 14, 2023 at 3:34:52 PM UTC-5, Keith Thompson wrote: > >> John Dill <jadi...@gmail.com> writes: > >> [...] > >> > I fall into the size_t camp (instead of 'int') for common looping of unsigned > >> > sequences. For size_t values where a -1 is needed for semantics, we use > >> > a preprocessor sequence to generate a signed version of size_t called > >> > ssize_t. > >> [...] > >> > >> POSIX defines a type ssize_t, a signed type that may or may not be the > >> signed type corresponding to size_t. It's defined in <sys/types.h> and > >> other headers. If there's any chance of your code being compiled under > >> POSIX, you might consider checking whether SSIZE_T is defined, and if so > >> just use the POSIX ssize_t (and be aware that it might not be the signed > >> type corresponding to size_t). Or pick a different name for your type. > > > > Agreed. We have something along these lines, with the build system > > handling the definitions of the HAVE tests. > > > > We lean on POSIX whenever possible, but not all environments support > > POSIX. > > > > \code > > /* If the <sys/types.h> header file is found, including the file > > should define the 'ssize_t' type. */ > > #if defined(HAVE_SYS_TYPES_H) > > # include <sys/types.h> > > #else > > # if !defined(HAVE_SSIZE_T) > > /* > > * The best candidate to define 'ssize_t' is 'ptrdiff_t'. If > > * 'ptrdiff_t' is not found, then the fallback type will be > > * 'long int'. > > */ > > # if defined(PTRDIFF_MAX) > > typedef ptrdiff_t ssize_t; > > # else > > typedef long int ssize_t; > > # endif > > # endif > > #endif > > C_STATIC_ASSERT (sizeof (ssize_t) == sizeof (size_t), > > ssize_t_is_compatible_with_size_t); > > \endcode > Rather than HAVE_SSIZE_T, you could check whether SSIZE_MAX is > defined in <limits.h>. > > ptrdiff_t has been standard since C89/C90. You can probably > get away with not testing for it. Note that PTRDIFF_MAX wasn't > introduced until C99, so you could get a false negative on some > old implementations. > > An alternative might be to check the values of UINT_MAX, ULONG_MAX, > and ULLONG_MAX vs. SIZE_MAX and use the corresponding signed type > int, long, or long long. That's if you want to be really picky, > but what you have should work on any realistic target platform. > > The name "ssize_t_is_compatible_with_size_t" is a bit misleading. > C type compatibility is defined very narrowly. A signed type is > never *compatible* with an unsigned type. What is "compatible" > supposed to mean in this context? > It means that the binary representation of the unsigned type is the same as the binary representation of the signed type when it is non-negative. So ssize_t ssz; size_t sz = sizeof(int); ssz = *(ssize_t *) &sz; puts sizeof(int) into ssz;
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-02-15 11:17 -0800 |
| Message-ID | <87lekyrb4z.fsf@nosuchdomain.example.com> |
| In reply to | #169279 |
Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
> On Wednesday, 15 February 2023 at 18:29:07 UTC, Keith Thompson wrote:
[...]
>> The name "ssize_t_is_compatible_with_size_t" is a bit misleading.
>> C type compatibility is defined very narrowly. A signed type is
>> never *compatible* with an unsigned type. What is "compatible"
>> supposed to mean in this context?
>>
> It means that the binary representation of the unsigned type is the same
> as the binary representation of the signed type when it is non-negative.
>
> So
> ssize_t ssz;
> size_t sz = sizeof(int);
> ssz = *(ssize_t *) &sz;
>
> puts sizeof(int) into ssz;
That's not what "compatible" means in C. I asked what the code John
Dill posted meant by "compatible". Are you familiar with that code,
including parts that haven't been posted?
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-02-15 11:32 -0800 |
| Message-ID | <87a61erag6.fsf@nosuchdomain.example.com> |
| In reply to | #169281 |
Keith Thompson <Keith.S.Thompson+u@gmail.com> writes:
> Malcolm McLean <malcolm.arthur.mclean@gmail.com> writes:
>> On Wednesday, 15 February 2023 at 18:29:07 UTC, Keith Thompson wrote:
> [...]
>>> The name "ssize_t_is_compatible_with_size_t" is a bit misleading.
>>> C type compatibility is defined very narrowly. A signed type is
>>> never *compatible* with an unsigned type. What is "compatible"
>>> supposed to mean in this context?
>>>
>> It means that the binary representation of the unsigned type is the same
>> as the binary representation of the signed type when it is non-negative.
>>
>> So
>> ssize_t ssz;
>> size_t sz = sizeof(int);
>> ssz = *(ssize_t *) &sz;
>>
>> puts sizeof(int) into ssz;
>
> That's not what "compatible" means in C. I asked what the code John
> Dill posted meant by "compatible". Are you familiar with that code,
> including parts that haven't been posted?
I think I misread the code. `sizeof (ssize_t) == sizeof (size_t)` is
the condition being asserted, and `size_t_is_compatible_with_size_t` is
the name associated with that assertion, not something that's defined
elsewhere.
ssize_t and size_t being the same size does not guarantee that the
binary representations are the same for common values. That's
guaranteed only if they are corresponding signed and unsigned types,
like long and unsigned long. Their representations are very likely to
match, but unless the code does some odd low-level stuff that's unlikely
to matter.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
| From | John Dill <jadill33@gmail.com> |
|---|---|
| Date | 2023-02-15 11:01 -0800 |
| Message-ID | <bc0d6df6-1856-4518-8d7d-f3d7febabaecn@googlegroups.com> |
| In reply to | #169278 |
On Wednesday, February 15, 2023 at 1:29:07 PM UTC-5, Keith Thompson wrote: > John Dill <jadi...@gmail.com> writes: > > On Tuesday, February 14, 2023 at 3:34:52 PM UTC-5, Keith Thompson wrote: > >> John Dill <jadi...@gmail.com> writes: > >> [...] > >> > I fall into the size_t camp (instead of 'int') for common looping of unsigned > >> > sequences. For size_t values where a -1 is needed for semantics, we use > >> > a preprocessor sequence to generate a signed version of size_t called > >> > ssize_t. > >> [...] > >> > >> POSIX defines a type ssize_t, a signed type that may or may not be the > >> signed type corresponding to size_t. It's defined in <sys/types.h> and > >> other headers. If there's any chance of your code being compiled under > >> POSIX, you might consider checking whether SSIZE_T is defined, and if so > >> just use the POSIX ssize_t (and be aware that it might not be the signed > >> type corresponding to size_t). Or pick a different name for your type. > > > > Agreed. We have something along these lines, with the build system > > handling the definitions of the HAVE tests. > > > > We lean on POSIX whenever possible, but not all environments support > > POSIX. > > > > \code > > /* If the <sys/types.h> header file is found, including the file > > should define the 'ssize_t' type. */ > > #if defined(HAVE_SYS_TYPES_H) > > # include <sys/types.h> > > #else > > # if !defined(HAVE_SSIZE_T) > > /* > > * The best candidate to define 'ssize_t' is 'ptrdiff_t'. If > > * 'ptrdiff_t' is not found, then the fallback type will be > > * 'long int'. > > */ > > # if defined(PTRDIFF_MAX) > > typedef ptrdiff_t ssize_t; > > # else > > typedef long int ssize_t; > > # endif > > # endif > > #endif > > C_STATIC_ASSERT (sizeof (ssize_t) == sizeof (size_t), > > ssize_t_is_compatible_with_size_t); > > \endcode > Rather than HAVE_SSIZE_T, you could check whether SSIZE_MAX is > defined in <limits.h>. Having the test be compiler local instead of autoconf style generated has its appeal. > ptrdiff_t has been standard since C89/C90. You can probably > get away with not testing for it. Note that PTRDIFF_MAX wasn't > introduced until C99, so you could get a false negative on some > old implementations. Nice find! > An alternative might be to check the values of UINT_MAX, ULONG_MAX, > and ULLONG_MAX vs. SIZE_MAX and use the corresponding signed type > int, long, or long long. That's if you want to be really picky, > but what you have should work on any realistic target platform. I appreciate really picky. > The name "ssize_t_is_compatible_with_size_t" is a bit misleading. > C type compatibility is defined very narrowly. A signed type is > never *compatible* with an unsigned type. What is "compatible" > supposed to mean in this context? That's a good point. A better term is "size equivalent" perhaps? Really appreciate the thoughts. Cheers! John D.
[toc] | [prev] | [next] | [standalone]
| From | Keith Thompson <Keith.S.Thompson+u@gmail.com> |
|---|---|
| Date | 2023-02-15 11:28 -0800 |
| Message-ID | <87edqqranm.fsf@nosuchdomain.example.com> |
| In reply to | #169280 |
John Dill <jadill33@gmail.com> writes:
> On Wednesday, February 15, 2023 at 1:29:07 PM UTC-5, Keith Thompson wrote:
>> John Dill <jadi...@gmail.com> writes:
[...]
>> > C_STATIC_ASSERT (sizeof (ssize_t) == sizeof (size_t),
>> > ssize_t_is_compatible_with_size_t);
>> > \endcode
[...]
>> The name "ssize_t_is_compatible_with_size_t" is a bit misleading.
>> C type compatibility is defined very narrowly. A signed type is
>> never *compatible* with an unsigned type. What is "compatible"
>> supposed to mean in this context?
>
> That's a good point. A better term is "size equivalent" perhaps?
I misread the arguments to the C_STATIC_ASSERT() macro; I thought you
were testing two different conditions. I see that
sizeof (ssize_t) == sizeof (size_t)
is the condition being tested, and
size_t_is_compatible_with_size_t
is a name assigned to that condition (used in an error message?).
How about "size_t_ssize_t_same_size"? (Yeah, it's a bit ugly.)
But is that really a requirement? Note that POSIX doesn't guarantee
that size_t and ssize_t have the same size. I'd be surprised by an
implementation in which their sizes differ. But if size_t and ssize_t
are the same size, then there will be sizes representable as a size_t
that exceed SSIZE_MAX; if that's a problem for real code, an
implementation might make ssize_t bigger than size_t.
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for XCOM Labs
void Void(void) { Void(); } /* The recursive call of the void */
[toc] | [prev] | [next] | [standalone]
Page 1 of 2 [1] 2 Next page →
Back to top | Article view | comp.lang.c
csiph-web