29
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

「2016年、C言語はどう書くべきか」をちょっと分析してみる (types編)

Last updated at Posted at 2016-02-23

Overview

原典は、https://matt.sh/howto-c (日本語訳を作ってくださっている方のページは http://postd.cc/how-to-c-in-2016-1/ )を、分析してみるシリーズです。

「2016年、C言語はどう書くべきか」をちょっと分析してみる (building編) では、リンク時の最適化 option (--flto)についての分析でした。

今回は、Writing code編です。

Types

#include <stdint.h>

で、定義された型を使いましょうとのこと。

c-langの説明から引用しますと、

名称 内容
intN_t 幅がNビット、詰め物ビットなし、2の補数で表現される、符号付き整数型。例えば、int8_tなら、厳密に幅が8ビットの符号付き整数型となる。
uintN_t 幅がNビットの符号なし整数型。
int_leastN_t 少なくとも幅がNビットの符号付き整数型。
uint_leastN_t 少なくとも幅がNビットの符号なし整数型。
int_fastN_t 少なくとも幅がNビットの最速符号付き整数型。
uint_fastN_t 少なくとも幅がNビットの最速符号なし整数型。
intptr_t voidへのポインタがこの型へ変換可能でかつ逆の変換も可能な符号付き整数型。
uintptr_t voidへのポインタがこの型へ変換可能でかつ逆の変換も可能な符号なし整数型。
intmax_t すべての符号付き整数型のすべての値を表現可能な符号付き整数型。
uintmax_t すべての符号なし整数型のすべての値を表現可能な符号なし整数

ポイント1:

  • charとか使うな。
  • 処理系によって変わるintとか使うな
  • byteは、uint8_t使え

ポイント2:

  • int_fast8_tとuint_fast8_tは、8bit幅とは限らず、8bit保持できる最速の方になる (platform依存)
  • int_leastN_tとuint_leastN_tは、"Least types provide you with the most compact number of bits for the type you request." つまり、N bitの幅の通りになる、のが普通の実装だそうです。
One thing to be aware of for fast types: it can impact certain test cases.

なお、fastと使うときは、テストケースにインパクトが有ることに注意しましょう、とのこと。
(実際にはplatformによって、幅が違うから。)

intにすべきか、そうでないか

The ISO/IEC 9899:1990 standard specified that the language should support four signed and unsigned integer data types- char, short, int, and long- but placed very little requirement on their size other than that int and short be at least 16 bits and long be at least as long as int and not smaller than 32 bits. For 16-bit systems, most implementations assigned 8, 16, 16, and 32 bits to char, short, int, and long, respectively. For 32-bit systems, the common practice has been to assign 8, 16, 32, and 32 bits to these types. This difference in int size can create some problems for users who migrate from one system to another which assigns different sizes to integer types, because the ISO C standard integer promotion rule can produce silent changes unexpectedly. The need for defining an extended integer type increased with the introduction of 64-bit systems.

ISO/IEC 9899:1990 standardでは、言語は4つのsignedとunsignedのinteger data typesであるchar, short, int, longをサポートすべきとしています。しかし、それらのサイズに関しては、ほんの少ししかrequirementを定めていません。

  • intとshortは少なくとも16bit

  • longは少なくともintと同じサイズで、32bitよりも短くはしない

  • 16 bit systemでは、多くの実装が、{char, short, int, long}={8,16,16,32}です。

  • 32 bit systemでは、多くの実装が、{char, short, int, long}={8,16,32,32}です。

このint sizeの差は、あるシステムから別のシステムへmigrateしたいユーザーに、いくつかの問題を引き起こします。とりわけ、intのサイズが異るシステムに。というのは、ISO C標準のintegerのpromotion ruleでは、静かに予期せぬ変化を起こすためです。64bit systemの導入に伴い、拡張integerを定義する必要が増えています。

例外としてcharを使うケース

  • 既存の(charが既に使われている)APIを使うとき
  • read-onlyの初期化を行うとき
const char *hello = "hello";

(というのは、Cのtype of stringのリテラル("hello")は char [] だからです)

ちなみにC11では、unicodeをサポートしていて、utf-8 stringのリテラルは同じくchar []とのこと。

const char *abcgrr = u8"abc😬";

のように、u8""でくくることで使える (余談: かつてのVC使いは、_T("")を思いだします。。。)

例外としてint, longなどを使うケース

If you are using a function with native return types or native parameters, use types as described by the function prototype or API specification.

nativeな戻り型や、nativeなparameterと共に関数を使う場合は、function prototypeやAPIの規定に従って型を使います。

符号について

unsigned long long int なんて使わずに、 uint64_tを使おうということだそうです。同意。。。

pointerの取り扱いについて

longなどに入れてpointerを計算するのではなく、

  • <stdint.h> で定義されたuintptr_t
  • stddef.hで定義された ptrdiff_t

を使うこと、とのことです。

ptrdiff_t diff = (uintptr_t)ptrOld - (uintptr_t)ptrNew;

とか

printf("%p is unaligned by %" PRIuPTR " bytes.\n", (void *)p, ((uintptr_t)somePtr & (sizeof(void *) - 1)));

みたいに。

ptrdiff_t とは

ptrdiff_t
Signed integral type of the result of subtracting two pointers.

のとおり、signedの整数の型であり、2つのポインターの差の結果を格納するための型とのこと。

system依存のある型

systemに応じて、32bit/64bitのように扱いたい時 (例えばポインタとか)は、longを使いたくなるかもしれないが、使うなということです。

代わりには、pointerの計算のところで書いた ptrdiff_t でpointerのoffsetを扱ったり、intptr_tを使えとのこと (uintptr_tのflavorから来ているとのこと)

ちなみに、 wikipedia のLP64の項目などを見るとわかりますが、platformによってかなり挙動が違いますので、こういうbest practiceには従ったほうが良いです。

29
32
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
29
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?