リリース・改善中
C ガイド · 3/6
この章は現在、英語でのみ提供しています。
In C, a type decides how many bytes a value occupies and how those bytes are interpreted. This chapter walks through integer and floating-point types, arrays, strings as character arrays, and the tools for grouping data: structs, unions, enums, and typedef.
The standard does not fix the exact size of integer types; it only guarantees minimum widths. Real sizes depend on the platform.
| Type | Guaranteed minimum | 64-bit Linux and macOS | 64-bit Windows |
|---|---|---|---|
char | 8 bits | 8 bits | 8 bits |
short | 16 bits | 16 bits | 16 bits |
int | 16 bits | 32 bits | 32 bits |
long | 32 bits | 64 bits | 32 bits |
long long | 64 bits | 64 bits | 64 bits |
The long column is the one that bites people when code moves between systems. When you need an exact width, use the fixed-width types from <stdint.h> such as int8_t, int32_t, and uint64_t. For object sizes and array indexes, use size_t from <stddef.h>, which is unsigned.
Unsigned integers wrap around modulo their range, which is well defined. Signed integer overflow, on the other hand, is undefined behavior. For floating point you have float, double, and long double; double is the usual default.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
#include <limits.h>
int main(void) {
printf("int: %zu bytes, max %d\n", sizeof(int), INT_MAX);
printf("long: %zu bytes\n", sizeof(long));
uint8_t small = 255;
small++; /* unsigned values wrap to 0 */
printf("small = %u\n", (unsigned)small);
int64_t big = INT64_C(9000000000);
printf("big = %" PRId64 "\n", big); /* format macro for fixed-width types */
double avg = 10 / 4; /* 2.0: integer division happens first */
double ok = 10 / 4.0; /* 2.5 */
printf("%.1f %.1f\n", avg, ok);
return 0;
}An array is a fixed number of same-typed elements laid out contiguously. Its size is set at declaration and never changes. If you provide fewer initializers than elements, the rest are zero.
int scores[5] = {90, 85, 77}; /* last two elements are 0 */
size_t n = sizeof scores / sizeof scores[0]; /* element count: 5 */
for (size_t i = 0; i < n; i++) {
printf("%zu: %d\n", i, scores[i]);
}
int grid[2][3] = {{1, 2, 3}, {4, 5, 6}}; /* two-dimensional array */
printf("%d\n", grid[1][2]); /* 6 */C does no bounds checking. Reading scores[5] compiles and may even appear to work, but it is undefined behavior. Also, when you pass an array to a function it decays into a pointer to its first element, so sizeof inside the function no longer gives you the element count. The convention is to pass the length alongside the array.
There is no dedicated string type. A string is a char array terminated by a null character, '\0'. The literal "hi" takes three bytes: h, i, and the terminator.
#include <stdio.h>
#include <string.h>
int main(void) {
char name[16] = "Kim"; /* a writable array */
const char *lang = "C"; /* a string literal: never modify it */
printf("%zu\n", strlen(name)); /* 3: the terminator is not counted */
printf("%zu\n", sizeof name); /* 16: the whole array */
char buf[32];
snprintf(buf, sizeof buf, "%s loves %s", name, lang); /* never writes past buf */
puts(buf);
if (strcmp(name, "Kim") == 0) { /* compare contents with strcmp, not == */
puts("same string");
}
return 0;
}strcpy and strcat never check the destination size, which makes overflows easy. Reaching for snprintf, which takes the buffer size, is a safer habit. Comparing strings with == compares addresses rather than contents, so use strcmp.
A struct groups values of different types. Access members with ., or with -> through a pointer. C99 designated initializers (.x = 1) let you initialize members by name, in any order.
An enum defines a set of named integer constants. A union overlays all its members on the same storage, so it holds only one of them at a time; it is normally paired with a tag that records which member is active. typedef gives a type a new name.
#include <stdio.h>
typedef enum { SHAPE_CIRCLE, SHAPE_RECT } ShapeKind;
typedef struct {
double x, y;
} Point;
typedef struct {
ShapeKind kind; /* tag: which union member is valid */
Point origin;
union {
double radius; /* SHAPE_CIRCLE */
struct { double w, h; } size; /* SHAPE_RECT */
} u;
} Shape;
double area(const Shape *s) {
switch (s->kind) {
case SHAPE_CIRCLE: return 3.14159265 * s->u.radius * s->u.radius;
case SHAPE_RECT: return s->u.size.w * s->u.size.h;
}
return 0.0;
}
int main(void) {
Shape c = { .kind = SHAPE_CIRCLE, .origin = { .x = 0, .y = 0 }, .u.radius = 2.0 };
Shape r = { .kind = SHAPE_RECT, .u.size = { .w = 3.0, .h = 4.0 } };
printf("%.2f %.2f\n", area(&c), area(&r));
printf("sizeof(Shape) = %zu\n", sizeof(Shape));
return 0;
}Passing a struct by value copies the whole thing, so pass large structs by pointer and add const when the function only reads. A struct can be larger than the sum of its members because the compiler inserts padding for alignment.
<stdint.h> for exact widths and size_t for sizes and indexes.'\0'-terminated char arrays; handle them with snprintf and strcmp.enum, and shorten type names with typedef.
コメント 0件
ログイン · ログインするとコメントできます。
最初のコメントを書いてみましょう。