web-dev-qa-db-ja.com

ポータブルCの定義

私は、たるんだグループの誰かと、激しく熱くなっている議論をしてきました-議論はこれです:

私の引数

  • 移植可能なコードとは、さまざまなコンパイラーでコンパイルされ、変更することなくさまざまなアーキテクチャーでまったく同じように実行されるコードです。
  • コードが整数型のsizeof(T)に依存している場合、移植性を保つためにstdint.hint8_tまたはint32_tのように
  • 重要なCプログラムのほとんどは、ある程度のビット単位の操作を伴うため、誰もがstdint.hについて知っておく必要があります

彼の引数

  • C規格には、「移植性を最大にするために標準型を使用する」と記載されています。
  • int32_tなどは、すべてのアーキテクチャでの存在が保証されているわけではないため、使用しないでください。
  • stdint.hはC99なので、組み込みシステムはC89のみをサポートしている可能性があるため、これは避ける必要があります。

私のカウンターは、型のサイズがわからない限り、コードが根本的に壊れる可能性があること、そしてstdint.hを使用しない場合でも、明示的にサイズが指定された型のtypedefを持つヘッダーファイルが常に存在することです(例Windows.h宣言INT8INT32[〜#〜] dword [〜#〜]等々)

私が得る唯一の返事は、あなたがint32_tを使用している場合、C標準によると移植性がないということです。型のサイズが原因で実行時の動作が変化しても、コードが移植可能ではないというわけではありません。

通常、私はこれを手放しますが、これは多くの新進のCおよびC++プログラマーがガイダンスのために来るフォーラムにあり、その多くは私が個人的に知っています。また、この男はCプログラマーのプロのトレーナーであると主張しているので、私はなおさら心配しています。

intまたはshortのような基本的なタイプを使用すると、コードはにならないことを他の方法で私はこの男に納得させることができますポータブルですか?

それは「ポータブル」の定義に要約されます-それは単にさまざまなコンパイラでコンパイルするのですか、それともコンパイルするすべてのプラットフォームで同じように実行する必要があるのですか?.

ランタイムの移植性が重要だと思っていたでしょう-あなたのコメントは何ですか?

6
rep_movsd

「さかのぼって」、8ビットから64ビットのプラットフォームで動作する小型デバイスデータベースの正確な型サイズを必要とする移植性の高いコードを作成する必要がありました。すべての変数の正確なサイズを義務付けるコーディング標準がありました。このアプローチにより、MISRAを(他の利点の中でも)合格することが容易になりました。

この作業を行うために、私はc89ビルド用に独自の "stdint.h"を作成して維持し、適切な#ifdefを使用して標準のものまたは "mine"を使用しました。

独自のstdint.hの使用が「移植可能」かどうかについては、適切なifdefがあれば、可能な限り移植可能です。 stdint.hがないと、Cにはプラットフォームに依存しないサイズの型がないため、「何かをする」必要があります。 int、shortなどにはCの標準サイズがなく、特定のサイズに依存している場合は、それらを使用することはできません。

5
Greg Kemnitz

私はあなたたち二人とも問題点を証明しようとしているのではないかと思います。 「移植性」はよくある誤解であり、「移植性」を損なうために特定のプラットフォームを離れる必要がないこともよくあります(主要なOSの主要なアップグレードを見てください)。

引数はビットのみに基づいています。この場合、ビット幅が異なるアーキテクチャ間を移動すると、「移植性」が損なわれる可能性があります( CHAR_BIT を参照)。

さらに、多くの標準(および多くの言語)には、何かがimplementation definedであることを示す多くのセマンティクスの句があります。利用可能になります)。

本当に技術的になりたいなら、Wordの「移植性」の意味を分解するべきだと思います。何かを移植することは、あるプラットフォームから別のプラットフォームに移動することです。

コードが移植可能であれば、問題なくコードを1つのプラットフォームから別のプラットフォームに移植できます(つまり、コードは期待どおりに実行されます)。しかし、だからといって コンパイラを変更する。コンパイラーを変更すると、コードが問題なく「移植」されることをもはや保証できないと想定されます。

私のコードがコンパイラ全体で期待どおりに機能することを保証しようとしている場合、私はテストしていません 携帯性 システム間 コンプライアンス 私がコーディングしている特定のC標準を持つコンパイラ間(つまり、C89/C99/ISO/ANSI/Embedded Cなど)。

Cは本来の目的のため、100%ポータブルではありません。ハードウェアにできるだけ近づけてください。

5
txtechhelp

プラットフォームにはありますか?

C + 11とC99以降、固定幅整数型は各言語のそれぞれの標準にあります。相手の最初の議論が理にかなっているとは思いません。

ただし、これらはオプションです。その幅のネイティブ整数型がない場合、それらは存在しません。それは完全に有効な反対意見です。

ネイティブintフレーバーが32ビットのプラットフォームで作成していて、後でネイティブ32ビットタイプのない64ビットプラットフォームをターゲットにしているとします。 int32_tを使用すると、コードはコンパイルされません。 intを使用すると、32ビットの想定を行わない限り、問題なく動作します。 intの勝利、それはもっとportable。一方、非コンパイルは、プログラムが失敗する可能性のある方法について、最も透過的で、最も迅速に表示され、修正が最も簡単な方法です。 32ビットを想定してintを使用した場合、プラットフォーム固有の恐ろしいランタイムバグがあります。楽しい。 int_32tで勝利。

したがって、それはトレードオフです。固定幅の整数を使用すると、コードが準拠するプラットフォームが少なくなりますが、一度実行すると期待どおりに機能することを確信できます。非固定幅の整数を使用すると、より多くのプラットフォームでコンパイルされますが、これらの異なるプラットフォームでは、さらに多くのQAを実行する必要があります。どちらがより移植性が良いかは、移植性が何を意味するかというあなたの考えに依存します。私はあなたに同意します。なぜなら、私はリスクを嫌い、静かな生活を望んでいるからです。

C89?

十分に公正で、あなたは対戦相手は非常に学術的な意味で正しいです。技術的には、K&R Cでコンパイルしないようにします。C89が登場した後でも、人々はK&Rの互換性を念頭に置いて作成していました。コードを改善する多くのクールな機能をあきらめたくなかったので、私たちは立ち止まりました。 Imho、古いコンパイラをターゲットにする必要があることがわかっている場合を除いて、C89の記述は正気ではありません(C + 11より前の記述はさらに不可解です)。これは、根拠のない学術的な会話の問題です。

ほとんどの重要なCプログラムにはいくつかの問題があります...

多分。私はバグが好きではないので、コードのどこかで可能な限り愚かなことをしたと思いがちです。安全のため、固定幅を使用します。しかし、Cプログラムは大きく異なります。重要なプログラムがすべてポインタを使用しているとは言えません。だから、これはあなたが撃墜されると期待できる種類の声明です。

3
Nathan Cooper

移植性は常にいくつかのプラットフォームの範囲内にあります。 Cは完全に移植可能な言語ではありません。 Cを実装できない(またはCを適切に実装できない)マシンを構築することは可能です。したがって、移植性の問題は常に、サポートするプラットフォームの範囲の1つです。

Cを使用することにより、Cコンパイラが機能するプラットフォームのサブセットをサポートします。明らかに。しかし、Cで行うことは、そのサポートを狭める可能性があります。

コードが整数型のsizeof(T)に依存している場合、移植性を保つために、_stdint.h_や_uint8_t_などの_uint32_t_の型を使用する必要があります

型のサイズに依存するコードを記述する場合、C自体と同じくらい移植性のあるコードを記述しているわけではありません。ご存知のとおり、C_標準では、_uint8_t_およびそのような型は必須ではありませんです。 C標準による。それらはオプション C99およびC11の機能です。そして、C++ 11以降、あなたが疑問に思っていた場合のために。

しかし、「標準に関する限り」の移植性は、必ずしも移植性のすべてではありません。結局のところ、これらのタイプをサポートできるプラットフォームとサポートするプラットフォームはたくさんあります。これらのプラットフォーム内でコードを移植できます。

実際に警告されているのは、サイズ付きの型にそれほど依存していないことです。あなたが警告されているのは、依存性型サイズです。 Cは型のサイズを定義していないため、プラットフォームを制限するのはthatです。 Cでは、個々のプラットフォームでこれを行うことができます。

したがって、高速の32ビット整数型に依存するコードはその性質上は、そのようなものを持たないプラットフォームには移植できません。この例として、VulkanはクロスプラットフォームグラフィックAPIとして課金します。そしてそうです。しかし、Vulkanはすべての型を_stdint.h_サイズの整数型で定義しています。どうして?

プラットフォームがthemをサポートできない場合、プラットフォームはcannotがVulkan期間をサポートするためです。そのため、VulkanがCが実行できるすべてのもので実行できるというふりをする意味はありません。

それは間違いではありません。コードのニーズに基づいて制限を設定するだけです。 Vulkanとの間でデータ構造を直接頻繁に送信しているため、実装が期待する/必要とするものと一致させる必要があります。したがって、Cプラットフォームは、これらに一致できる型をサポートする必要があります。

同時に、明示的に特定のサイズの整数needsが必要な処理を行っていない場合は、intします。 _int_leastXX_t_型は必須であり、整数の範囲に関するほとんどの問題を処理できます。

intshortなどの基本的な型を使用すると、コードを移植できないことを他の方法でこの人に納得させることができますか?

これらの型を使用すると、移植性のないことを行う場合にのみ移植性がなくなります。

たとえば、ビット操作はCで明確に定義されています。intの特定のビット数はそうではありません。したがって、次のコード:

_unsigned int i = 1 << 19;
_

そのプラットフォームでsizeof(unsigned int)が20ビット以上である限り、完全に明確に定義されています。したがって、これが当てはまるanyプラットフォームは問題ありません。

対照的に:

_uint32_t i = 1 << 19;
_

プラットフォームが_uint32_t_をサポートしている場合のみ、明確に定義されたコードです。バイトサイズが異常な場合(9ビットと18ビットは不明なバイトサイズではありません)、_uint32_t_をサポートできません。したがって、そのコードは機能しません。ただし、intのサイズが36ビットであった可能性があるため、最初のケースではうまくいった可能性があります。

特定のサイズの整数型に制限することにより、それらのサイズの整数型をサポートするプラットフォームにも制限されます。基本的な整数型を使用する場合、それらの型が使用するものすべてに対して「十分に大きい」プラットフォームに制限されます。

それで、どちらがよりポータブルですか?サイズなしのものを十分な大きさの整数を持つanything(これはCをサポートする)で実行できる場合、サイズ付きのものの方が移植性が高いと主張するのは困難です。一方、サイズが1つに制限されるのは、32ビット整数をサポートできるプラットフォームのみです。そのコードは実際には32ビットを使用していませんが。

後者の利点の1つは、サイズ付きの型がサポートされていない場合、ハードコンパイルエラーが発生することです。対照的に、intが十分に大きくない場合、目に見えない実装定義の動作になります。 C++ 11は、_static_assert_を使用してその問題の解決策を取得しました。これにより、任意のコンパイル時のものでのコンパイルが妨げられる可能性があります。 intのサイズが特定の用途に十分な大きさであるように。

3
Nicol Bolas

コードで型サイズまたは表現についてany仮定言語定義が保証する範囲を超えてを作成する必要があるとすぐに、移植性を制限します。 intオブジェクトがexactly 32ビット幅でなければならないことをコードが想定している場合、それは簡単に移植できません1 16ビットintsのシステム、または_CHAR_BIT_が8ではないシステムなど.

OTOH、intが値の範囲__[-32767..32767]_を格納できる必要があるとのみ想定している場合、コードは変更なしでany(準拠)システムに移植できます。

固定サイズの型は、サポートされているプラ​​ットフォームでの使用を容易にしますが、コードの移植性は向上しません一般的に

編集

Rep_movsdの場合 章と節

5.2.4.2.1整数型のサイズ<limits.h>

1以下の値は、 _#if_ 前処理ディレクティブでの使用に適した定数式に置き換えられます。また、 _CHAR_BIT_ _MB_LEN_MAX_ を除いて、同じ型の式に置き換えます。整数の昇格に従って変換された対応する型のオブジェクトである式と同様に。 これらの実装定義の値は、表示されている値と絶対値(絶対値)が等しいか、それより大きくなければなりません、同じ符号。
...
—タイプintのオブジェクトの最小値
INT_MIN -32767 // −(215 − 1)

—タイプintのオブジェクトの最大値
_INT_MAX +32767 // 215 − 1_

...
6.2.5タイプ
...
5タイプ_signed char_として宣言されたオブジェクトは、「プレーン」_char_オブジェクトと同じ容量のストレージを使用します。 A '' plain '' _int_オブジェクトは、実行環境のアーキテクチャによって提案された自然なサイズを持っています(_INT_MIN_から_INT_MAX_の範囲の値を含めるのに十分な大きさ)ヘッダー_<limits.h>_)で定義されています。

強調が追加されました。

最近のほとんどのアーキテクチャでは、intは少なくとも32ビット幅ですが、普遍的ではありません。私は90年代にその方法で噛まれました。 MacOS 8とWin 3.1で実行する必要があるコードに取り組んでいました。私は、32ビットintを想定して、Macでは問題なく動作するが、16ビットintをまだ使用しているWindowsマシンで失敗したコードをいくつか記述しました。




  1. つまり、ソースを変更せずに、単純に新しいターゲット用に再コンパイルできます。
0
John Bode