为什么sizeof操作员返回的结构尺寸大于结构成员的总尺寸?
我知道C++ 中的"未定义行为"几乎可以让编译器做任何想做的事情.但是,我遇到了让我感到惊讶的崩溃,因为我认为代码足够安全.
在这种情况下,真正的问题仅发生在使用特定编译器的特定平台上,并且仅在启用了优化时才发生.
我尝试了几件事来重现问题并将其简化到最大程度.这是一个名为的函数的摘录Serialize,它将获取bool参数,并将字符串true或复制false到现有的目标缓冲区.
如果bool参数是未初始化的值,那么这个函数是否会在代码审查中,没有办法告诉它实际上可能会崩溃?
// Zero-filled global buffer of 16 characters
char destBuffer[16];
void Serialize(bool boolValue) {
// Determine which string to print based on boolValue
const char* whichString = boolValue ? "true" : "false";
// Compute the length of the string we selected
const size_t len = strlen(whichString);
// Copy string into destination buffer, which is zero-filled (thus already null-terminated)
memcpy(destBuffer, whichString, len);
}
Run Code Online (Sandbox Code Playgroud)
如果使用clang 5.0.0 +优化执行此代码,它将/可能崩溃.
boolValue ? "true" …
我在这里浏览strlen代码,想知道是否真的需要代码中使用的优化?例如,为什么下面这样的东西不能同样好或更好?
unsigned long strlen(char s[]) {
unsigned long i;
for (i = 0; s[i] != '\0'; i++)
continue;
return i;
}
Run Code Online (Sandbox Code Playgroud)
较简单的代码对编译器进行优化是否更好或更容易?
strlen链接后面页面上的代码如下所示:
Run Code Online (Sandbox Code Playgroud)/* Copyright (C) 1991, 1993, 1997, 2000, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. Written by Torbjorn Granlund (tege@sics.se), with help from Dan Sahlin (dan@sics.se); commentary by Jim Blandy (jimb@ai.mit.edu). The GNU C Library is free software; you can redistribute it and/or modify it under …
继我之前的问题之后,大多数评论都说“不要这样做,你处于一种不确定的状态,你必须杀死一切并重新开始”。还有一个“安全”的解决方法。
我不明白的是为什么分段错误本质上是不可恢复的。
写入受保护内存的时刻被捕获 - 否则,将SIGSEGV不会被发送。
如果可以捕获写入受保护内存的时刻,我不明白为什么 - 理论上 - 它不能在某个低级别上恢复,并且不能将 SIGSEGV 转换为标准软件异常。
请解释为什么在分段错误之后程序处于不确定状态,因为很明显,在内存实际更改之前抛出了错误(我可能是错的,不明白为什么)。如果它被抛出,人们可以创建一个程序来更改受保护的内存,一次一个字节,出现分段错误,并最终重新编程内核 - 这种安全风险并不存在,因为我们可以看到世界仍然存在。
SIGSEGV)?鉴于此代码:
#include <string.h>
int equal4(const char* a, const char* b)
{
return memcmp(a, b, 4) == 0;
}
int less4(const char* a, const char* b)
{
return memcmp(a, b, 4) < 0;
}
Run Code Online (Sandbox Code Playgroud)
x86_64上的GCC 7引入了第一种情况的优化(Clang已经做了很长时间):
mov eax, DWORD PTR [rsi]
cmp DWORD PTR [rdi], eax
sete al
movzx eax, al
Run Code Online (Sandbox Code Playgroud)
但第二种情况仍然是memcmp():
sub rsp, 8
mov edx, 4
call memcmp
add rsp, 8
shr eax, 31
Run Code Online (Sandbox Code Playgroud)
是否可以对第二种情况应用类似的优化?什么是最好的装配,有没有明确的理由为什么它没有完成(由GCC或Clang)?
在Godbolt的Compiler Explorer上看到它:https://godbolt.org/g/jv8fcf
我有一个结构必须填充到 64K 才能完美地适合嵌入式项目,以便它填充闪存块。所以有一个#define将结构中的元素加起来使用sizeof()并确定pad[]最后需要多大才能使总大小为64K。
例如 :
#define SIZE_OF_MY_PAD (0x10000 - (sizeof(uint16_t) + sizeof(uint8_t)*32 + ... ))
typedef struct {
uint16_t firstElement;
uint8_t secondElementArray[32];
...
uint8_t pad[SIZE_OF_MY_PAD];
};
Run Code Online (Sandbox Code Playgroud)
这在很长一段时间内一直有效,直到突然我们在某些构建配置中根本不需要垫,因为它已经正好是 64k。这会导致代码失败,因为我们的编译器(不是 GCC)不允许pad[0].
我曾尝试过各种方法来创建一个预处理价值,我可以在使用#if声明中当检测到,但它总是失败,因为虽然sizeof()是合法的#define,它不是法律#if。
有没有办法在C中找出动态分配内存的大小?
例如,之后
char* p = malloc (100);
Run Code Online (Sandbox Code Playgroud)
有没有办法找出与之相关的内存大小p?
在gcc-strict-aliasing-and-casting-through-a-union中,我问是否有人遇到过通过指针进行联合惩罚的问题.到目前为止,答案似乎是否定的.
这个问题是广泛的:你有任何关于gcc和严格走样恐怖故事?
背景:引用AndreyT在c99-strict-aliasing-rules-in-c-gcc中的答案:
"严格的别名规则植根于自[标准化]时代开始以来C和C++中存在的标准部分.禁止通过另一种类型的左值访问一种类型的对象的条款存在于C89/90中(6.3 )以及C++ 98(3.10/15)......并非所有编译器都希望(或敢于)强制执行或依赖它.
好吧,gcc现在敢于用它的-fstrict-aliasing开关来做到这一点.这引起了一些问题.例如,请参阅有关Mysql错误的优秀文章 http://davmac.wordpress.com/2009/10/,以及http://cellperformance.beyond3d.com/articles/2006/06/understanding中同样出色的讨论.-strict-aliasing.html.
其他一些不太相关的链接:
重复一遍,你有自己的恐怖故事吗?当然,没有表示的问题-Wstrict-aliasing是优选的.其他C编译器也很受欢迎.
6月2日补充:迈克尔伯尔的答案中的第一个链接,确实有资格作为恐怖故事,可能有点过时(从2003年开始).我做了一个快速测试,但问题显然已经消失了.
资源:
#include <string.h>
struct iw_event { /* dummy! */
int len;
};
char *iwe_stream_add_event(
char *stream, /* Stream of events */
char *ends, /* End of stream */
struct iw_event *iwe, /* Payload */
int event_len) /* Real size of payload …Run Code Online (Sandbox Code Playgroud) 我是C的新手,它是继Java之后的第二种高级编程语言.我已经掌握了大部分基础知识,但无论出于何种原因,我无法将单个字符写入屏幕内存.
该程序使用Turbo C for DOS编译,运行速度为120mhz的Am486-DX4-100.该显卡是使用Trio32芯片的非常标准的VLB Diamond Multimedia Stealth SE.
对于操作系统,我运行的PC-DOS 2000加载了ISO代码页.我正在使用标准的MDA/CGA/EGA/VGA 80列文本模式运行.
这是我编写的程序:
#include <stdio.h>
int main(void) {
unsigned short int *Video = (unsigned short int *)0xB8000;
*Video = 0x0402;
getchar();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
正如我所说,我对C很新,所以如果我的错误显而易见,我道歉,我无法找到一个可以理解的如何做到这一点的可靠来源.
据我所知,在x86平台上的实模式下,文本模式的屏幕内存从0xB8000开始.每个字符存储在两个字节中,一个用于字符,一个用于背景/前景.我的想法是将值0x0402(应该是一个红色的笑脸)写入0xB8000.这应该放在屏幕的左上角.
我已经考虑了屏幕可能滚动的可能性,因此在执行时会立即以两种方式删除我的角色.要解决此问题,我尝试过:
我可以读取并打印我写入内存的值,所以它显然仍然在内存中,但无论出于何种原因,我都没有在屏幕上显示任何内容.我显然做错了,但我不知道会出现什么问题.如果需要任何其他细节,请询问.感谢您提供任何可能的帮助.
对齐对C++ 11的性能是否真的重要?
在Stroustrup的书中有一条建议,要求从最大到最小的结构中对成员进行排序.但我想知道是否有人进行了测量,以确定是否会产生任何影响,并且在编写代码时是否值得考虑.