warning: cast from pointer to integer of different size
警告:ポインタ型を型幅の違う整数型にキャストした
[-Wpointer-to-int-cast]
■(int)NULL
#include <stdio.h>
#include <string.h>
void f1(void){
char buf[1024];
memset(buf,(int)NULL,sizeof(buf));//NG
}
「0 はマジックナンバーなので使用禁止!」と
教育された初級者が
0と書けず
NULLと書き、
コンパイラに警告されて (int)NULL とキャストする場合が多いです。
➡(int)NULL➡0に修正
void f2(void){
char buf[1024];
memset(buf,0,sizeof(buf));//OK
}
0はマジックナンバーではないので素直にべたで0と書く。
■(char)NULL
size_t f3_strlen(char *s)
{
char *p;
for (p = s; *p != (char)NULL; p++)//NG
;
return p - s;
}
「文字列の最後にはNULL文字がある」と教育された初級者が
‘\0’と書かずに
NULLと書き、
コンパイラに警告されてキャストする場合が多いです。
➡(char)NULL➡’\0’に修正
size_t f4_strlen(char *s)
{
char *p;
for (p = s; *p != '\0'; p++)//OK
;
return p - s;
}
「文字列の最後には終端文字’\0′がある」と教育しましょう。
■問題:文字列にキャストすると?
warning: suspicious usage of ‘sizeof(A*)’; pointer to aggregate
警告:余計なキャストが疑わしい
[misc-sizeof-expression]
問題:次のプログラムは何と表示されるでしょうか?
#include <stdio.h>
#include <string.h>
#define STRING (const char *)"123456789abcdef"
int main(void)
{
printf("%ld\n",sizeof( "123456789abcdef"));
printf("%ld\n",sizeof((char *)"123456789abcdef"));
printf("%ld\n",sizeof(STRING));
printf("%ld\n",strlen(STRING));
}
sizeof((char *)“123456789abcdef”)は余計なキャストをしているため、文字列リテラル”123456789abcdef”は無視され
sizeof(char *)と同じ結果が求まります。
sizeof(STRING)も同様ですが、
キャストがマクロで隠されるのでより問題の発見が難しくなります。
●解答
■(void *)NULL
warning: redundant cast to the same type
警告:冗長キャストがコードを汚す
[google-readability-casting]
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *cp = (char *)malloc(sizeof(char)*(int)1024);
if((char *)cp == (char *)NULL){
printf("メモリ確保失敗\n");
return (int)1;
}
memset((void *)cp,(int)'\0',sizeof(char)*1024);
strncpy((char *)cp,(const char *)"a-b-c",(int)6);
char *sp = strchr((char *)cp,(int)'-');
if((char *)sp == (char *)NULL){
printf((const char *)"'-'検索失敗\n");
return (int)1;
}
printf((const char *)"%s\n",(char *)sp);
if((char *)cp != (char *)NULL){
free((void *)cp);
}
return (int)0;
}
●例1:malloc()/free()にキャストしたがる理由
C-FAQ7.7
http://www.kouno.jp/home/c_faq/c7.html#7
MEM02-C. Immediately cast the result of a memory allocation function call into a pointer to the allocated type
ここの末尾のコメント欄の議論が面白い
●例2:NULLにキャストしたがる理由
NULLについて
http://f4.aaacafe.ne.jp/~pointc/log1018.html
●例3:文字定数にキャストしたがる理由
推測⇒
C言語では文字定数がint型だと知らないから
int型に明示的にキャストする?
●例4:memset/cpy/cmpの引数にキャストしたがる理由
推測⇒
K&Rという初代C言語では汎用ポインタの void * がなく
char *で代用していた大昔の習慣が現代に継承されている?
➡不要なキャストを削除すると読みやすい
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *cp = malloc(1024);
if(cp == NULL){
printf("メモリ確保失敗\n");
return 1;
}
memset(cp,'\0',1024);
strcpy(cp,"a-b-c");
char *sp = strchr(cp,'-');
if(sp == NULL){
printf("'-'検索失敗\n");
free(cp);
return 1;
}
printf("%s\n",sp);
free(cp);
}
不要キャストを削除してサッパリしませんか?
■mallocにキャストしないとコンパイルエラーになる?
➡C言語なのにC++コンパイラ使ってる?
ソースコード.cppと
サフィックスを.cppにすると
C++コンパイラが起動されるので
サフィックスを.cにして下さい。
➡50年以上前のK&Rコンパイラを使ってる?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//void *を返すmalloc関数の戻り値にわざわざキャストした例。
//尚、mallocのNULLチェックとfree処理はここでは省略する
typedef struct {
char data[1024];
} tag_t;
int main(void){
char *cp = (char *)malloc(sizeof(char)*strlen("abc")+1);
strcpy(cp,"abc");
short *sp = (short *)malloc(sizeof(short));
*sp = 0x1234;
long *lp = (long *)malloc(sizeof(long));
*lp = 0x1234567887654321;
tag_t *tp = (tag_t *)malloc(sizeof(*tp));
tp->data[0] = 'X';
printf("%s:%x:%lx:%c\n",cp,*sp,*lp,tp->data[0]);
}
(1)このようなキャストが必要なコンパイラは
K&Rという古いコンパイラかもしれません。
⇒そんな古いコンパイラはスミソニアン博物館に寄付しましょう。
(2)このようなキャストが必要なコンパイラは
C++コンパイラかもしれません。
⇒Visual Studio使用者でC言語のつもりでC++コンパイラを起動している場合がありました。
(3)将来CからC++へ移行するかもしれないので今からキャストすると言う人はYAGNI原則を
勉強しましょう。
■今時のコンパイラはmallocにキャスト不要
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//void *を返すmalloc関数の戻り値の不要キャストを削除した例。
//尚、mallocのNULLチェックとfree処理はここでは省略する
typedef struct {
char data[1024];
} tag_t;
int main(void){
char *cp = malloc(strlen("abc")+1);
strcpy(cp,"abc");
short *sp = malloc(sizeof(short));
*sp = 0x1234;
long *lp = malloc(sizeof(long));
*lp = 0x1234567887654321;
tag_t *tp = malloc(sizeof(*tp));
tp->data[0] = 'X';
printf("%s:%x:%lx:%c\n",cp,*sp,*lp,tp->data[0]);
}
今のCコンパイラはこのキャストの無いコードを正常にコンパイル出来ます。
エラーが出るのは太古のコンパイラか
C++コンパイラを使用している場合です。
参考: