1から100の整数を出力してください( ただし5つの異なる方法を用いて )の1
LL DiverのLTの1コマで、「1から100の整数を出力してください( ただし5つの異なる方法を用いて )」という話がありました。バカらしいの込みでもいいから5つ以上つくってみたいと思います。
まずはシンプルにforループを使用したもの。
はじめに
for(i = 0; i < 100; i++)
って書いちゃって、0から99の整数を出力してしまうというポカをしてしまいました。
MISRA-C 2012購入した
勤め先でもMISRA-C導入を視野に入れているというのもあり、先日購入した。 英語だから読むのがおっくうだけど、読んでいこう。(日本語訳版が早々に出ると嬉しい。)
多次元配列のちょっと変わった参照の仕方
いきなりですが、配列の値を参照するための a[1] というのは、 *(a + 1) を少しでも気楽に書けるようにするための構文らしいです(こういうのをシンタックスシュガーと呼ぶらしい)。
でもって、*(a + 1) と *(1 + a) の値は同じになりますね?ここで、*(1 + a) を[]使った形に直すと 1[a] になります。実は a[1] と 1[a] は同じ意味になってしまうのだ!
とまあ、ここまでは
- 作者: 前橋和弥
- 出版社/メーカー: 技術評論社
- 発売日: 2001/01
- メディア: 単行本
- 購入: 22人 クリック: 147回
- この商品を含むブログ (75件) を見る
といっても、構文規則は同じなので恐れることはない。
#include <stdio.h> int main() { int a[2][3][4] = { { { 0, 1, 2, 3, }, { 4, 5, 6, 7, }, { 8, 9, 10, 11, }, }, { { 12, 13, 14, 15, }, { 16, 17, 18, 19, }, { 20, 21, 22, 23, }, }, }; printf("%d\n", a[1][2][3]); printf("%d\n", (*(a + 1))[2][3]); printf("%d\n", (*(*(a + 1) + 2))[3]); printf("%d\n", *(*(*(a + 1) + 2) + 3)); printf("%d\n", *(*(1[a] + 2) + 3)); printf("%d\n", *(2[1[a]] + 3)); printf("%d\n", 3[2[1[a]]]); return 0; }
どの printf でも 23 が出力されます。だからなんだっていうんだって話ですがね。
そういえば、*(a + 1)[2][3]だと *((a + 1)[2][3]) になるみたい。ここは実行してみてから気づいた。
じつはそんなに不思議な現象ではないのかも
このコードについて???? コンパイラの不思議 - goinger的日記を読んで軽く気になったので -fno-builtin でビルトインなものを消してみたりして考えみました。たどり着いたのは、C言語はファイル別にコンパイルするというだけの理由ではないかというもの。
たとえば、
int add(int a, int b) { return a + b; }
という関数を add.c として保存して、
void add();
main()
{
add();
}
を add.c とは別に test.c として作成する。
そのうえで
$ gcc test.c add.c
としてもエラーはでない。
コンパイルするときはプロトタイプ宣言のみしか見ていないからこれでも動くのでしょう。今回は、 puts() であると警告が入るので特別に感じたのではないかと考えます。
ちょっと奇をてらって
構造体変数に自分自身のポインタを持たせて、ごにょごにょしてみた。
#include <stdio.h> #include <stdlib.h> struct hoge { struct hoge *self; int i; struct hoge *(*print)(struct hoge *); }; struct hoge *p(struct hoge *v) { printf("%d\n", v->i); v->i += 2; return v; } int main() { struct hoge *val; val = malloc(sizeof(struct hoge)); val->self = val; val->i = 3; val->print = p; val->print(val->self)->print(val->self)->print(val->self); // これでも動く不思議 return 0; }
実行すると
$ gcc --version gcc (GCC) 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2) Copyright (C) 2006 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. $ gcc -Wall -ansi -o test test.c $ ./test 3 5 7 $
警告も吐きません。GJ