未定义的行为?

时间:2016-12-10 09:40:49

标签: c undefined-behavior

阅读this后,我的理解是以下程序应该调用UB。我是对的吗?

int main(void)
{
        char *ptr = "ABCD";
        ptr = 'A';
        printf("%c\n", ptr);
}

感谢。

3 个答案:

答案 0 :(得分:3)

你是对的,发布的代码确实以多种方式调用未定义的行为。

您可能不希望在认为此类代码正常的公司工作。

当我使用默认的clang选项编译代码时,我收到4个警告:

clang -O2 -funsigned-char -std=c11 -Weverything -Wno-padded -Wno-shorten-64-to-32 -Wno-mis\
sing-prototypes -Wno-vla -Wno-missing-noreturn -Wno-sign-conversion -Wno-missing-variable-\
declarations -Wno-unused-parameter -Wwrite-strings -lm -o ub2 ub2.c
ub2.c:3:11: warning: initializing 'char *' with an expression of type 'const char [5]' dis\
cards qualifiers [-Wincompatible-pointer-types-discards-qualifiers]
    char *ptr = "ABCD";
          ^     ~~~~~~
ub2.c:4:9: warning: incompatible integer to pointer conversion assigning to 'char *' from \
'int' [-Wint-conversion]
    ptr = 'A';
        ^ ~~~
ub2.c:5:5: warning: implicitly declaring library function 'printf' with type 'int (const c\
har *, ...)'
    printf("%c\n", ptr);
    ^
ub2.c:5:5: note: include the header <stdio.h> or explicitly provide a declaration for 'pri\
ntf'
ub2.c:5:20: warning: format specifies type 'int' but the argument has type 'char *' [-Wfor\
mat]
    printf("%c\n", ptr);
            ~~     ^~~
            %s
4 warnings generated.

其中3个警告表示可能存在未定义的行为:

  • 为指针'A'分配整数值会调用未定义的行为,但转换为空指针的整数常量0除外。有些系统会触发某些值的异常,有些系统会将整数值存储到指针的位置,不能依赖它。您将看到像ptr = (char*)0x0040006C;这样的代码,它们可以在为其定制的特定系统上正确编译,但它仅适用于特定的编译器/目标组合。

  • 传递%c转换说明符的指针被明确描述为在C标准中调用未定义的行为。指针可能以不同于printf值的方式传递给int,例如,在不同的寄存器集中,因此printf将不会收到指向要作为字符打印的指针。即使正确转换为'A',此也可能不是(int)ptr

  • 在范围内调用printf而没有适当的声明会调用未定义的行为。编译器根据传递的参数推断出的隐式原型可能与printf使用的varargs调用约定不兼容。在致电<stdio.h>之前,您必须包含printf或至少提供有效的原型。

在较小的说明中,还有一些评论:

  • "ABCD"是一个字符串文字。一定不能写。为了与大量遗留代码兼容,C标准(不情愿地)给它一种char[5]类型,它应该是const char[5]。这解释了为什么默认情况下你没有在char *ptr = "ABCD";上收到警告,但是允许编译器比标准更严格并警告程序员这一点是明智的。 const正确性可能需要在大型项目中进行大量更改,但可以防止潜在的未定义行为并提高编译器优化代码的能力。

  • 0返回main()是隐含的,因为C99,但它被认为是具有明确return 0;来表示成功的cood风格。

答案 1 :(得分:1)

c-string是一系列char。由char '\0'终止。

char *ptr = "ABCD";

创建一个包含5个字符的数组。 {'A', 'B', 'C', 'D', '\0'}静态内存中的某个地方,并将第一个字符(又名。'A')的地址分配给ptr。

当你这样做时

ptr = 'A';

您将'A'分配给ptr,它不是有效指针或c字符串,因此de-referencing指针会导致未定义的行为。

另外,C是一种打字语言,你不能把任何东西放进去。将'A'分配给ptr后,无法保证。 ptr将等于'A'ptr的类型为char *'A'的类型为char。你不能混合这些类型。

char *ptr = 'A';
if (ptr == 'A') // this is undefined behavior
  *ptr; // same here

如果你想做你想做的事,你必须写下来。

char c = 'A';
char *ptr = &c; // here ptr is not a valid c-string, it's just a pointer for one char

printf("%c", *ptr);

答案 2 :(得分:-1)

这里ptr指向程序的数据部分(只读)部分中的某个位置。 你修改了ptr =&#39; A&#39 ;;这里ptr指向ascii值,即65.So ptr指向65位置的值,因此是一个未定义的行为