为什么的Visual C的隐式转换++警告从常量无效**到void *在C,但不是在C ++? [英] Why does Visual C++ warn on implicit cast from const void ** to void * in C, but not in C++?
问题描述
摘要
在Microsoft Visual Studio中的C / C ++编译器在警告 C4090 当C程序试图的指针指针转换常量
数据(如常量无效**
或为const char **
)以无效*
(尽管这种类型实际上不是一个指向常量
)。更奇怪的是,相同的编译器默默接受相同的code编译为C ++。
什么是这种不一致的原因,为什么Visual Studio的(不像其他编译器)与隐式转换指针问题的指针的常量
到无效*
?
详细信息
我在这一个变量参数列表传递C字符串读入一个数组(由被调用的va_arg
循环)的C程序。由于C-字符串类型为const char *
,即跟踪他们的数组类型的为const char **
。这与常量
内容指向字符串数组本身是动态分配的(与释放calloc
)和I 免费
在函数返回(在C字符串后已被处理)之前。
当我编译这个code与 cl.exe时
(在Microsoft Visual C ++),即使是很低的警戒线,在免费
调用触发警告 C4090 。由于免费
需要无效*
,这告诉我,编译器不喜欢,我已经转换成一个为const char **
到无效*
。我创建了一个简单的例子来证实这一点,我在其中尝试将常量无效**
转换为无效*
/ * cast.c - 可一个const无效**隐式转换为void *? * /INT主要(无效)
{
常量无效** P = 0;
无效* Q;
Q =磷; 返回0;
}
然后我如下,证实这是什么触发警告编译它:
> CL cast.c
微软(R)32位C / C ++优化编译器版本为16.00.40219.01的80x86
版权所有(C)微软公司。版权所有。cast.c
cast.c(7):警告C4090:'=':不同的常量预选赛
微软(R)增量链接器版本10.00.40219.01
版权所有(C)微软公司。版权所有。/out:cast.exe
cast.obj
上警告C4090微软文档说:
此发出警告C程序。在C ++程序,编译器会发出错误:C2440
。
块引用>这是有道理的,因为C ++是一种比C强类型语言,并允许使用C潜在危险的隐式转换用C是不允许++。微软的文档使它看起来像警告 C2440 在C触发同一code,或code的一个子集,这将引发错误 C2440在C ++中的。
我这样想着,直到我试图编译我的测试程序作为C ++(在
/ TP
标志执行此操作):> CL / TP cast.c
微软(R)32位C / C ++优化编译器版本为16.00.40219.01的80x86
版权所有(C)微软公司。版权所有。cast.c
微软(R)增量链接器版本10.00.40219.01
版权所有(C)微软公司。版权所有。/out:cast.exe
cast.obj在同一code编译为C ++,没有错误或警告。可以肯定,我重建,告诉编译器为积极警告尽可能:
> CL / TP /华尔街cast.c
微软(R)32位C / C ++优化编译器版本为16.00.40219.01的80x86
版权所有(C)微软公司。版权所有。cast.c
微软(R)增量链接器版本10.00.40219.01
版权所有(C)微软公司。版权所有。/out:cast.exe
cast.obj它成功默默的。
那些构建均与微软的Visual C ++的Windows XP计算机于2010年防爆preSS版的
cl.exe时
Windows 7的机器上,但同样的错误出现,在这两个的Visual Studio .NET 2003的cl.exe时
和Visual C ++ 2005例preSS版的cl.exe时
。因此,似乎这发生在所有版本(虽然我没有在一切可能的版本测试),而不是与Visual Studio是建立在我的机器的方式有问题。同样的code编译没有一个Ubuntu 11.10系统(版本字符串
海湾合作委员会(Ubuntu的/ Linaro的4.6.1-9ubuntu3)4.6.1 $ C在GCC 4.6.1问题$ C>),设置为警告尽最大可能地,为C89,C99和C ++:
$ GCC -ansi -pedantic -Wall -Wextra -o投cast.c
cast.c:在函数'主':
cast.c:6:11:警告:变量'Q'设置,但不使用[-Wunused,但是设置变量]$ GCC -std = C99 -pedantic -Wall -Wextra -o投cast.c
cast.c:在函数'主':
cast.c:6:11:警告:变量'Q'设置,但不使用[-Wunused,但是设置变量]$ G ++ -x C ++ -ansi -pedantic -Wall -Wextra -o投cast.c
cast.c:在函数'廉政的main():
cast.c:6:11:警告:变量'Q'设置,但不使用[-Wunused,但是设置变量]它警告说,
①
永远不会被分配后读取,但这一警告是有道理的,是不相关的。除了没有引发海湾合作委员会的警告启用所有警告,并在任何海合会或MSVC不会触发警报在C ++中,在我看来,从指针转换为指针为const到
无效*
不应该被认为在所有问题,因为在无效*
是一个指向非 -常量
,指针的指针常量也是一个指向非 -常量
在我的现实世界的code(不是例子),我可以用
的#pragma
指令,或有明确的转换这沉默,或作为编译C ++(嘿嘿),或者我可以忽略它。但我宁愿没有做任何的那些事情,至少没有之前我明白为什么会这样。 (为什么不使用C ++发生!)一个可能,部分原因发生对我说:不像C ++,C允许从
隐式转换的void *
来的指针到的数据类型。所以我可以有一个指针隐式地从为const char **
转换为无效*
,然后隐式地从<$转换C $ C>无效* 到的char **
,从而可以修改它指向的指针不断的数据,没有一个演员。这将是坏的。但我看不出这是任何比这都有C的弱类型安全允许的其他各种事情变得更糟。我想也许这样的警告使得有选择不警告当非感 -
无效
指针类型转换为无效*
:/ * cast.c - 可一个const无效**隐式转换为void *? * /INT主要(无效)
{
常量无效** P = 0;
无效* Q;
Q =磷; 返回0;
}&GT; CL /华尔街voidcast.c
微软(R)32位C / C ++优化编译器版本为16.00.40219.01的80x86
版权所有(C)微软公司。版权所有。voidcast.c
微软(R)增量链接器版本10.00.40219.01
版权所有(C)微软公司。版权所有。/out:voidcast.exe
voidcast.obj然而,如果这是故意的,则:
为什么微软的文档显示,code生产这种警告用C C ++中产生错误?
此外忽视或燮pressing警告,没有任何合理的替代方法,当一个人必须
免费
非 -常量
指针非 -常量
指针常量
数据(如在我的现实世界的情况)?如果这样的事情在C ++中发生的事情,我可以存储在变量参数列表中的一些高层次的STL容器,而不是一个数组传递的字符串。对于没有进入C ++ STL和不以其他方式使用高层次的集合C程序,诸如此类的事情是不是一个合理的选择。一些程序员在警告作为错误的企业/组织的政策工作。 C4090 与
/ W1
启用连。人们一定遇到过这一点。什么是那些程序员呢?解决方案显然,这简直是在VC ++中的错误。
如果您声明
为const char ** X;
的结果是指向了只读指针字符,而且它本身不是一个只读指针(我使用术语只读,因为常量
-ness长期推动了被指向的字符错误的概念,是恒定的,而这是一般假..常量
与引用和指针是参考或指针的财产,不能说明所指向的或引用的数据的数量不同)。任何读/写指针可被转换为
无效*
和VC ++有没有真正的理由在编译code时发出警告,无论是在<$ ç$ C> C 也不C ++
模式。请注意,这不是一个正式的问题,因为标准并不强制其警告应该或不应该发行,因此编译器可以自由地发出警告,完全有效的code仍保持兼容。 VC ++居然发出这些警告的有效的C过多++ code ...
Summary
The C/C++ compiler in Microsoft Visual Studio gives warning C4090 when a C program tries to convert a pointer to pointer to
const
data (likeconst void **
orconst char **
) tovoid *
(even though such a type is not actually a pointer toconst
). Even more strangely, the same compiler silently accepts identical code compiled as C++.What is the reason for this inconsistency, and why does Visual Studio (unlike other compilers) have a problem with implicitly converting a pointer to pointer to
const
into avoid *
?Details
I have a C program in which C-strings passed in a variable argument list are read into an array (by a loop in which
va_arg
is invoked). Since the C-strings are of typeconst char *
, the array that keeps track of them is of typeconst char **
. This array of pointers to strings withconst
content is itself allocated dynamically (withcalloc
) and Ifree
it before the function returns (after the C-strings have been processed).When I compiled this code with
cl.exe
(in Microsoft Visual C++), even with a low warning level, thefree
call triggered warning C4090. Sincefree
takes avoid *
, this told me that the compiler didn't like that I had converted aconst char **
to avoid *
. I created a simple example to confirm this, in which I try to convert aconst void **
to avoid *
:/* cast.c - Can a const void** be cast implicitly to void* ? */ int main(void) { const void **p = 0; void *q; q = p; return 0; }
I then compiled it as follows, confirming that this was what triggered the warning:
>cl cast.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. cast.c cast.c(7) : warning C4090: '=' : different 'const' qualifiers Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:cast.exe cast.obj
Microsoft's documentation on warning C4090 says:
This warning is issued for C programs. In a C++ program, the compiler issues an error: C2440.
That makes sense, since C++ is a more strongly typed language than C, and potentially dangerous implicit casts allowed in C are disallowed in C++. Microsoft's documentation makes it seem like warning C2440 is triggered in C for the same code, or a subset of the code, that would trigger error C2440 in C++.
Or so I thought, until I tried compiling my test program as C++ (the
/TP
flag does this):>cl /TP cast.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. cast.c Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:cast.exe cast.obj
When the same code is compiled as C++, no error or warning occurs. To be sure, I rebuilt, telling the compiler to warn as aggressively as possible:
>cl /TP /Wall cast.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. cast.c Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:cast.exe cast.obj
It succeeds silently.
Those builds were with the Microsoft Visual C++ 2010 Express Edition's
cl.exe
on a Windows 7 machine, but the same errors occur on a Windows XP machine, in both Visual Studio .NET 2003'scl.exe
and Visual C++ 2005 Express Edition'scl.exe
. So it seems this happens on all versions (though I have not tested on every possible version) and is not a problem with the way Visual Studio is set up on my machines.The same code compiles without a problem in GCC 4.6.1 on an Ubuntu 11.10 system (version string
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1
), set to warn as aggressively as possible, as C89, C99, and C++:$ gcc -ansi -pedantic -Wall -Wextra -o cast cast.c cast.c: In function ‘main’: cast.c:6:11: warning: variable ‘q’ set but not used [-Wunused-but-set-variable] $ gcc -std=c99 -pedantic -Wall -Wextra -o cast cast.c cast.c: In function ‘main’: cast.c:6:11: warning: variable ‘q’ set but not used [-Wunused-but-set-variable] $ g++ -x c++ -ansi -pedantic -Wall -Wextra -o cast cast.c cast.c: In function ‘int main()’: cast.c:6:11: warning: variable ‘q’ set but not used [-Wunused-but-set-variable]
It does warn that
q
is never read from after being assigned, but that warning makes sense and is unrelated.Besides not triggering a warning in GCC with all warnings enabled, and not triggering a warning in C++ in either GCC or MSVC, it seems to me that converting from pointer to pointer to const to
void *
should not be considered a problem at all, because whilevoid *
is a pointer to non-const
, a pointer to a pointer to const is also a pointer to non-const
.In my real-world code (not the example), I can silence this with a
#pragma
directive, or an explicit cast, or by compiling as C++ (heh heh), or I can just ignore it. But I'd rather not do any of those things, at least not before I understand why this is happening. (And why it doesn't happen in C++!)One possible, partial explanation occurs to me: Unlike C++, C allows implicit casting from
void *
to any pointer-to-data type. So I could have a pointer implicitly converted fromconst char **
tovoid *
, and then implicitly converted fromvoid *
tochar **
, thereby making it possible to modify constant data it points to pointers to, without a cast. That would be bad. But I don't see how that is any worse than all sorts of other things that are allowed by C's weaker type-safety.I guess maybe this warning makes sense given the choice not to warn when a non-
void
pointer type is converted tovoid *
:/* cast.c - Can a const void** be cast implicitly to void* ? */ int main(void) { const void **p = 0; void *q; q = p; return 0; }
>cl /Wall voidcast.c Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.40219.01 for 80x86 Copyright (C) Microsoft Corporation. All rights reserved. voidcast.c Microsoft (R) Incremental Linker Version 10.00.40219.01 Copyright (C) Microsoft Corporation. All rights reserved. /out:voidcast.exe voidcast.obj
And yet, if that is intentional, then:
Why does the Microsoft documentation indicate that code producing this warning in C produces an error in C++?
Besides ignoring or suppressing the warning, is there any reasonable alternative, when one must
free
a non-const
pointer to non-const
pointer toconst
data (as in my real-world situation)? If something like this happened in C++, I could store the strings passed in the variable argument list in some high-level STL container instead of an array. For a C program without access to the C++ STL and which doesn't otherwise use high-level collections, that sort of thing is not a reasonable option.Some programmers work under a corporate/organizational policy of treating warnings as errors. C4090 is enabled even with
/W1
. People must have encountered this before. What do those programmers do?
解决方案Apparently this is simply a bug in VC++.
If you declare
const char **x;
the result is a pointer to a "read-only" pointer to chars, and it's not itself a "read-only" pointer (I use the term "read-only" becauseconst
-ness term pushes the wrong concept that the character being pointed to is constant while this is false in general...const
with references and pointers is a property of the reference or of the pointer and tells nothing about constness of the pointed-to or referenced data).Any read/write pointer can be converted to a
void *
and VC++ has no real reason to emit a warning when compiling that code, neither inC
nor inC++
mode.Note that this is not formally a problem because the standard doesn't mandate which warnings should or should not be issued and therefore a compiler is free to emit warnings for perfectly valid code still remaining compliant. VC++ actually emits a plethora of those warnings for valid C++ code...
这篇关于为什么的Visual C的隐式转换++警告从常量无效**到void *在C,但不是在C ++?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!