我有一个代码,其中有一个缓冲区,我正在try 将常量字符串复制到其中,如下所示:

#include <stdio.h>

typedef struct _BIGWORD {
    unsigned char Byte[53]; //size of constant string
} BIGWORD;

int main() {
    char cBuffer[64] = { 0 };

    BIGWORD *bwBufferCast = (BIGWORD *)cBuffer;
    
    *bwBufferCast = *(BIGWORD *){ "I am trying to copy this whole text inside a buffer!" };

    printf("text: %s\n", cBuffer);

    return 0;
}

这个不错,但我不知道是怎么回事.它是一个字节接一个字节地复制常量字符串,还是一次全部复制,或者只是巧合,因为它在那里,而我不会在真实的场景中工作.

我知道我可以创建类似于:char cBuffer[64] = "this is an array!"的字符array.我想按需将常量字符串放入缓冲区中.

我试图向代码中添加一些其他常量字符串,以判断它是否会影响结果,但没有.

推荐答案

关于什么是"未定义的行为",什么不是,在 comments 中似乎有很多混淆之处,所以让我一行行地介绍一下:

  • BIGWORD* bwBufferCast = (BIGWORD*)cBuffer;
    This is valid C since all manner of wild and crazy pointer casts are allowed in C (C17 6.3.2.3 §7).

    但是,此指针转换在某些情况下可能会调用未定义的行为,因为您开始的字符数组可能不对齐,并且 struct 类型可能有对齐要求.如果发生这种情况,一些CPU可能会在指针分配本身上设置指令trap .在其他CPU上,稍后在取消引用指针时可能会遇到问题.

  • (BIGWORD*) { "I am trying to copy this whole text inside a buffer!" };
    This is invalid C and will not compile cleanly. You create a compound literal consisting of a pointer. Initialization of that pointer (a so-called scalar) is done "as if by assignment" (C17 6.7.9 §11). Specifically, you are trying to initialize a BIGWORD* with a char*.

    然后我们可以判断有效赋值的规则(C17 6.5.16.1),并发现对于在赋值期间允许的隐式指针转换,指针需要兼容.它们不是(C17 6.2.7),所以这是违反约束的,编译器必须发出诊断.

    违反约束仍然会导致二进制可执行文件的程序是不符合C语言的,并且标准对任何行为都没有保证.

  • *(BIGWORD*)是可疑的.同样存在前面提到的潜在对齐问题,如果 struct 的字符串文字没有对齐,这将是未定义的行为.

    但也很可疑,因为您使用与声明的有效类型不同的类型对对象进行左值访问.正常情况下,我们可能会将其称为所谓的"严格混叠违规",What is the strict aliasing rule?.Tl;dr违反类型系统规则,导致未定义的行为.这可能会导致编译器生成错误的代码.

    但碰巧的是,这一行是一个严格的别名违规,因为(幸运的是)您设法满足了该规则的一个例外(C16 6.5§7).我们有一个 struct ,一个聚合类型,但有一个例外:"在其成员中包含上述类型之一的聚合或联合类型".其中"上述类型"包括"与对象的有效类型相对应的有符号类型或无符号类型的类型".成员为unsigned char[]的 struct 是与对象的有效类型char[]相对应的无符号类型.

  • 这里有*bwBufferCast个和上面一样的问题.潜在的错位,可疑但不严格的混叠违规.


结论:

这个程序不能很好地工作,因为它不能编译.使用一致的编译器(GCC 13.3-std=c17 -pedantic-errors),我得到预期的诊断消息:

错误:从不兼容的指针类型‘char*’初始化‘BIGWORD*’{AKA‘STRUCT_BIGWORD*’}[-WinCompatible-POINTER-TYPE]

如果您无论如何都运行了可执行文件,并且它没有因未对齐而出错,那么您可能仍然会得到预期的结果,要么是运气不好,要么是通过编译器扩展得到的保证.

还请注意,"我只得到了一个警告"仍然意味着程序可能是无效的C,没有保证的行为.退房What must a C compiler do when it finds an error?英镑

C++相关问答推荐

设计处理各种数据类型的方法和数据 struct

Apple Libm的罪恶功能

编译SDL 2时缺少SDL_ttf

ATTiny1606定时器TCA 0中断未触发

GCC预处理宏和#杂注GCC展开

如果我释放其他内容,返回值就会出错

二进制计算器与gmp

对重叠字符串使用MemMove

为什么我可以在GCC的标签后声明变量,但不能声明Clang?

是否定义了此函数的行为?

为四维数组中的Dim-1和Dim-3重新分配空间

int * 指向int的哪个字节?

当我在34mb的.mp4文件中使用FREAD时,我得到了一个分段错误,我如何解决它?

变量值不正确的问题

在C中,为什么这个带有递增整数的main函数从不因溢出而崩溃?

clion.我无法理解 Clion 中发生的 scanf 错误

C 中类型说明符的顺序重要吗?

当循环变量在溢出时未定义时,可以进行哪些优化?

如何确保 gcc + libc 对于多字节字符串使用 UTF-8,对于 wchar_t 使用 UTF-32?

如何在C中以0x格式打印十六进制值