我写了一个C程序如下:
void foo(int *a) {
if (a[1000] == a[1000]) {
printf("Hello");
}
}
int main() {
int *a;
foo(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我期待这个程序崩溃,因为我没有在&a [1000]分配内存,但程序实际上没有崩溃并打印"Hello".我用命令编译了程序
gcc -O0 foo.c
Run Code Online (Sandbox Code Playgroud)
可能是什么原因?
c memory-management compiler-optimization undefined-behavior
我已经看到过类似的帖子,但是我发现了一些差异,使我误入歧途。
我有以下代码:
char * token_one = strtok(my_buffer, " ,.-");
char * token_two = strtok(NULL, " ,.-");
free(token_one);
free(token_two);
Run Code Online (Sandbox Code Playgroud)
我看到有人在帖子中说不应释放与strtok一起使用的变量,但是为什么在执行此代码时却得到此信息:
free(token_one) 没有错误
free(token_two)我得到“ 无效指针 ”
为什么我没有收到错误消息free(token_one)?处理此问题的正确方法是什么?
考虑一些使用未初始化堆栈变量的非常简单的代码(或更复杂的代码,请参见下文1),例如:
int main() { int x; return 17 / x; }
Run Code Online (Sandbox Code Playgroud)
这是 GCC 发出的 ( -O3):
mov eax, 17
xor ecx, ecx
cdq
idiv ecx
ret
Run Code Online (Sandbox Code Playgroud)
以下是 MSVC 发出的内容 ( -O2):
mov eax, 17
cdq
idiv DWORD PTR [rsp]
ret 0
Run Code Online (Sandbox Code Playgroud)
作为参考,以下是 Clang 发出的内容 ( -O3):
ret
Run Code Online (Sandbox Code Playgroud)
问题是,所有三个编译器都检测到这是一个未初始化的变量就好了 ( -Wall),但实际上只有一个编译器基于它执行任何优化。
这让我有点难堪……我认为几十年来为未定义行为而争论的所有内容都是为了允许编译器优化,但我看到只有一个编译器关心优化甚至是最基本的 UB 情况。
为什么是这样?如果我想要Clang 以外的编译器优化 UB 的这种情况,我该怎么办?有什么方法可以让我真正获得 UB 的好处,而不仅仅是任何一个编译器的缺点?
1显然,对于某些人来说,这对于SSCCE来说太过分了,无法理解实际问题。如果你想要一个更复杂的这个问题的例子,在程序的每次执行中都不是未定义的,只需稍微按摩一下。例如:
int main(int argc, char …Run Code Online (Sandbox Code Playgroud) Foo1.hpp:
#pragma once
#include <string>
enum class Foo1 {
A, B, C
};
// Commented out to avoid compiler error
//inline Foo1 fFromStr(const std::string& a) {
// if (a == "A") return Foo1::A;
// if (a == "B") return Foo1::B;
// else return Foo1::C;
//}
inline std::string fToStr(const Foo1 a) {
switch (a) {
case Foo1::A: return "A";
case Foo1::B: return "B";
default : return "C";
}
}
Run Code Online (Sandbox Code Playgroud)
Foo2.hpp:
#pragma once
#include <string>
enum class Foo2 {
A, …Run Code Online (Sandbox Code Playgroud) 考虑以下代码:
int main() {
int *i = nullptr;
delete i;
}
Run Code Online (Sandbox Code Playgroud)
问题:
此代码打印"等于"和"1 0".
为什么会发生这种情况1 != 0呢?
if(2/2 == 2/2.0)
printf("equal \n");
printf("%d %d", 2/2, 2/2.0);
Run Code Online (Sandbox Code Playgroud) void first(){
int x;
int *p;
p= &x;
scanf("%d",p);
printf("The value in x or *p is: %d\n",x);
}
void second(){
int x;
int *ptr;
scanf("%d",&x);
printf("The value in *ptr is: %d\n",*ptr);
}
int main(){
first();
second();
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,second()函数是miss行为.我为x赋值的变量*ptr以及x 赋予了什么值.为什么?
我的意思是问它是否遵循一些特定的算法,实际上不是垃圾.
换句话说,"垃圾"值究竟是如何存在的?考虑不调用UB,如果读取垃圾值,该值的来源是什么?
所以我一直在读一本 C++14 书(这是我图书馆最新的一本),尽管我比它深了大约 100-200 页,但有些东西一直在我的脑海中游动,但在某些时候它提到了这一点打脸:
i++ + ++i;
Run Code Online (Sandbox Code Playgroud)
它说不要这样做,但我还是这样做了。在 Visual Studio C++ 和在线 C++ 编译器(特别是 onlinegdb)中,它给我3when int i = 1;,但是当我分配 时i = i++ + ++i;,在线编译器给我4,Visual Studio 给我5......让我们看看, ifi++递增i但 是原始值,并且++i递增i和是新的和改进的 i,那么如果int i = 1;,我们会这样做:
1 + 2;
Run Code Online (Sandbox Code Playgroud)
并且i会是3!两个编译器都这么说。但 i = i++ + ++i;给出了不同的答案!我希望我可以验证这一点,但我无法在脑海中计算分配和增量。也许这就是编译器正在做的事情,一个在表达式中分配然后递增,另一个则做相反的事情。PEMDAS 与 PEDMAS 的精神对比。
所以我知道这是未定义行为的字面教科书示例,但无论如何我都会问一个问题:在实践中是否有未定义行为 的使用,是否有充分的理由使用这段特定的代码(可能没有)因为它的可怕性质),关于这段代码(及其交易)还有什么需要注意的吗?
我正在阅读有关static_cast运算符的内容.
考虑以下示例:
#include <iostream>
class B { };
class D : public B
{
public:
void fun()
{
std::cout<<"fun() is called\n";
}
};
void f(B* pb,D* pd)
{
D* pd2=static_cast<D*>(pb);
B* pb2=static_cast<B*>(pd);
pd2->fun();
}
int main()
{
B b;
D d;
f(&b,&d);
}
Run Code Online (Sandbox Code Playgroud)
它说:
在下面的示例中,行D*pd2 = static_cast(pb); 是不安全的,因为D可以有不在B中的字段和方法.但是,行B*pb2 = static_cast(pd); 是一个安全的转换,因为D总是包含所有的B.
与dynamic_cast相反,没有对pb的static_cast转换进行运行时检查.pb指向的对象可能不是D类型的对象,在这种情况下使用*pd2可能是灾难性的.例如,调用作为D类成员但不是B类成员的函数可能会导致访问冲突.
我在gcc 4.8.1和MSVS 2010上尝试了它并获得输出fun()被调用.那么这个程序会调用未定义的行为吗?我的程序可以在运行时崩溃吗?C++标准对此有何看法?如果我理解错误,请纠正我.
c++ inheritance static-cast undefined-behavior language-lawyer
c ×6
c++ ×5
pointers ×2
c++11 ×1
c++14 ×1
gcc ×1
inheritance ×1
null-pointer ×1
optimization ×1
static-cast ×1
strtok ×1
variables ×1
visual-c++ ×1