一个简单的程序:
int main()
{
long i = i;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编译为C不会出现错误,也不会出现警告.
$ gcc -Wall -Wextra -pedantic 1.c
Run Code Online (Sandbox Code Playgroud)
编译为C++会发出警告:
$ c++ -Wall -Wextra -pedantic 1.c
1.c: In function ‘int main()’:
1.c:3:7: warning: ‘i’ is used uninitialized in this function [-Wuninitialized]
long i = i;
Run Code Online (Sandbox Code Playgroud)
在两种情况下,变量i似乎都是0,尽管在c ++中它可能是未初始化的.我实际上在我的一个功能中犯了这样的错字,很难找到它.我该怎么做才能避免这种情况?我希望至少有一个警告.此外,Clang在任何一种情况下都不会给出任何警告(c或c ++).是否有标准的特定部分说明了这种行为?
编辑:尝试了类似的东西:
$ cat 1.c
int main(void)
{
int k = k + 0;
int i = i + 1;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
警告(在C中)仅针对"i"生成.
$ gcc -Wall -Wextra 1.c
1.c: In function ‘main’:
1.c:4:6: …Run Code Online (Sandbox Code Playgroud) 在全局命名空间中给出以下声明:
constexpr int x = x;
Run Code Online (Sandbox Code Playgroud)
这个结构良好吗?
草案C++ 14标准部分3.6.2 [basic.start.init]说:
具有静态存储持续时间(3.7.1)或线程存储持续时间(3.7.2)的变量应在任何其他初始化发生之前进行零初始化(8.5).[...]
似乎使得示例定义良好的是x在常量初始化期间使用其自己的值初始化,这将0归因于零初始化.
error: the value of 'x' is not usable in a constant expression
constexpr int x = x;
^
Run Code Online (Sandbox Code Playgroud) 我在cppreference.com上看到了以下示例
int x; // OK: the value of x is indeterminate
int y = x; // undefined behavior
Run Code Online (Sandbox Code Playgroud)
这里int y = x;是未定义的行为,因为它x是未初始化的.
但,
unsigned char c; // OK: the value of c is indeterminate
unsigned char d = c; // OK: the value of d is indeterminate
Run Code Online (Sandbox Code Playgroud)
这里unsigned char d = c;是不确定的行为,但unsigned char c;也是一个未初始化的变量.
那么,为什么unsigned char d不确定的价值呢?
当我使用Clang(-O3)或MSVC(/O2)编译并运行此代码时...
#include <stdio.h>
#include <time.h>
static int const N = 0x8000;
int main()
{
clock_t const start = clock();
for (int i = 0; i < N; ++i)
{
int a[N]; // Never used outside of this block, but not optimized away
for (int j = 0; j < N; ++j)
{
++a[j]; // This is undefined behavior (due to possible
// signed integer overflow), but Clang doesn't see it
}
}
clock_t const finish = …Run Code Online (Sandbox Code Playgroud) 我正在阅读JP Mueller和J. Cogswell撰写的"C++ All-in-One for Dummies"并偶然发现:
#include <iostream>
using namespace std;
int main()
{
int ExpensiveComputer;
int CheapComputer;
int *ptrToComp;
...
Run Code Online (Sandbox Code Playgroud)
这段代码首先初始化所有涉及的东西 - 两个整数和一个指向整数的指针.
只是为了确认,这是一个错误,应该读作'......通过声明',对吧?对我来说,这样的基本错误仍然会出现在书中,这一点很奇怪.
C++20 标准草案的[basic.scope.pdecl]/1在注释中包含以下(非规范性)示例(合并拉取请求 3580之前的部分引用,请参阅此问题的答案):
unsigned char x = x;
Run Code Online (Sandbox Code Playgroud)
[...] x 用它自己的(不确定的)值初始化。
这实际上在 C++20 中有明确定义的行为吗?
通常T x = x;,由于x的值在初始化完成之前是不确定的,因此表单的自初始化具有未定义的行为。评估不确定的值通常会导致未定义的行为([basic.indent]/2),但在[basic.indent]/2.3中有一个特定的例外,它允许直接unsigned char从unsigned char具有不确定值的左值初始化变量(导致使用不确定值初始化)。
这本身并不会因此导致不确定的行为,但会为其他类型T不属于无符号窄字符类型或std::byte如int x = x;。这些注意事项也适用于 C++17 及之前的版本,另请参阅底部的链接问题。
然而,即使对于unsigned char x = x;,当前草案的[basic.lifetime]/7说:
类似地,在对象的生命周期开始之前 [...] 使用不依赖于其值的泛左值的属性是明确定义的。在以下情况下,程序具有未定义的行为:
泛左值用于访问对象,或
[...]
这似乎意味着x示例中的that值只能在其生命周期内使用。
[...]
类型 T 的对象的生命周期在以下情况下开始:
- [...] 和
- 它的初始化(如果有)完成(包括空初始化)([dcl.init]),
[...]
因此x的生命周期仅在初始化完成后才开始。但是在引用的例子中 …
在C++ 11标准中(最接近的草案是N3337)部分1.2 规范性参考文献说:
以下参考文件对于本文件的应用是必不可少的.凡是注日期的引用文件,仅引用的版本适用.凡是不注日期的引用文件,其最新版本(包括所有的修改单)适用于本标准.
但是没有关于如何应用参考文献的指南.简单的情况是当C++ 11明确引用回引用时,例如在3.9.1 基本类型部分中它说:
[...]有符号和无符号整数类型应满足C标准第5.2.4.2.1节中给出的约束.
但是,没有明确参考的其他情况呢?例如,C++ 11使用单词indeterminate值,但它没有定义术语.规范性参考文献包括:
- ISO/IEC 9899:1999,编程语言 - C.
[...]
- ISO/IEC 9899:1999/Cor.3:2007(E),编程语言 - C,技术勘误3
和C99(草案c99标准)确实对部分中的不确定值有一个定义,3.17.2其中说:
要么是未指定的值,要么是陷阱表示
如果通过引用C99定义C++ 11来定义不确定值是否正确,就像这个答案似乎对于bit的定义一样?如果是的话,什么陷阱表示这是覆盖在部分6.2.6.1第5下代表处类型的C99?
慷慨的解读是,只要C++ 11中没有任何内容与规范性引用冲突就适用,这是正确的解释吗?一些答案是什么是C++中的不确定行为?它与未定义的行为有什么不同?似乎意味着慷慨的阅读,虽然在一些答案中语言有点宽松,所以很难说出某些要点究竟是什么.
根据http://en.cppreference.com/w/cpp/language/zero_initialization,我无法理解何时以及为什么我的班级中的某个成员是零初始化的.
考虑以下测试程序:
#include <iostream>
#include <stdio.h>
class MyTest {
private:
const static unsigned int dimension = 8;
void (* myFunctions [dimension])();
public:
MyTest() {}
void print() {
for(unsigned int i=0; i < MyTest::dimension; i++) {
printf("myFunctions[%d] = %p\n", i, this->myFunctions[i]);
}
}
};
int main() {
//We declare and initialize an object on the stack
MyTest testObj = {};
testObj.print();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我声明一个类有一个包含签名"void functionname()"的8个函数指针的数组.当我宣布和初始化类的对象main作为MyTest testObj = {};或者MyTest testObj;,我希望它是零初始化,即所有指针都是空指针.
但是,在带有g++ -m32 …
是使用未初始化的变量作为src对memcpy用C未定义行为?
void foo(int *to)
{
int from;
memcpy(to, &from, sizeof(from));
}
Run Code Online (Sandbox Code Playgroud) 我刚刚在一个函数中找到了这行代码,这让我很困惑.这在任何情况下都有意义,还是未定义的行为?
char * acFilename = acFilename;
Run Code Online (Sandbox Code Playgroud)
编辑:编译器抱怨警告C4700,我正在使用未初始化的变量.