坦率地说,这样的代码是有效还是产生UB?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct __attribute__((__packed__)) weird_struct
{
int some;
unsigned char value[1];
};
int main(void)
{
unsigned char text[] = "Allie has a cat";
struct weird_struct *ws =
malloc(sizeof(struct weird_struct) + sizeof(text) - 1);
ws->some = 5;
strcpy(ws->value, text);
printf("some = %d, value = %s\n", ws->some, ws->value);
free(ws);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我永远不会认为它对这样的事情是有效的,但似乎SystemV消息队列就是这样做的:参见手册页.
所以,如果SysV msg队列可以做到这一点,也许我也可以这样做?我想我发现通过网络发送数据很有用(因此__attribute__((__packed__))
).
或者,这可能是SysV msg队列的特定保证,我不应该在其他地方做类似的事情吗?或者,也许这种技术可以使用,只有我做错了?我想出来我最好问一下.
这- 1
在malloc(sizeof(struct weird_struct) + sizeof(text) - 1)
是因为我考虑到一个字节分配反正感谢unsigned char value[1]
,所以我可以从减去它 …
c arrays undefined-behavior language-lawyer flexible-array-member
如果我想从标准输入到向量读取所有整数,我可以使用方便:
vector<int> v{istream_iterator<int>(cin), istream_iterator()};
Run Code Online (Sandbox Code Playgroud)
但我们假设我只想读取n
整数.手动打字循环是我得到的一切吗?
vector<int> v(n);
for(vector<int>::size_type i = 0; i < n; i++)
cin >> v[i];
Run Code Online (Sandbox Code Playgroud)
还是有更多的右手方式来做到这一点?
我正在读这个volatile
关键字不适合线程同步,事实上根本不需要这些关键字.
虽然我知道使用这个关键字是不够的,但我不明白为什么它完全没必要.
例如,假设我们有两个线程,线程A仅从共享变量读取,线程B仅写入共享变量.通过例如pthreads互斥锁实现适当的同步.
IIUC,没有volatile关键字,编译器可能会查看线程A的代码并说:"这里的变量似乎没有被修改,但是我们有很多读取; 让我们只读一次,缓存值并优化所有后续读取."它也可以查看线程B的代码并说:"我们在这里有很多写这个变量但没有读取; 因此,不需要写入值,因此我们可以优化所有写入."
两种优化都是不正确的.和都 挥发性会阻止一个人.所以,我可能会得出这样的结论:虽然volatile
不足以同步线程,但仍然需要在线程之间共享任何变量.(注意:我现在读到,实际上并不需要volatile
防止写入成功;所以我没有想法如何防止这种不正确的优化)
我明白我错在这里.但为什么?
我曾经相信它确实存在但是...我无法明确说明它.
man 3 exit
并man 2 _exit
详细说明了进程终止的影响,但没有提到内存泄漏.
Posix走近了:它提到了这个:
在进程被销毁之前,应该在进程中创建的内存映射取消映射.
[TYM] [Option Start]在调用进程中映射的任何类型内存块都应取消映射,就像
munmap()
隐式调用它们取消映射它们一样.[选项结束]
混合这个man 3 malloc
:
通常,
malloc()
从堆中分配内存,并根据需要使用调整堆的大小sbrk(2)
.当分配大于MMAP_THRESHOLD
字节的内存块时,glibcmalloc()
实现将内存分配为私有匿名映射使用mmap(2)
.
因此,我们可以得出结论,如果malloc
调用,mmap
则进程终止可能会进行相应的调用munmap
,但是......(a)此POSIX规范中的这个"可选功能"标记令人担忧,(b)这是mmap
怎么回事sbrk
?(c)Linux不是100%符合POSIX,所以我不确定是否强制将Linux文档与Posix规范混合使用
我问的原因是这个......当图书馆通话失败时,我是否可以退出?
if(somecall() == -1) {
error(EXIT_FAILURE, errno, "Big fat nasty error.\n");
}
Run Code Online (Sandbox Code Playgroud)
还是我上去栈确保一切都一路攀升到main()
是free()
"d和来电exit
或error
在main()
?
前者简单得多.但是为了让前者感到轻松,我想在明确提到的文档中找到它,这不是一个错误,这样做是安全的.正如我所说的那样,事实上,文档明确提到了一些肯定会被清理的保证,但没有提到这个特定的保证让我感到不安.(这不是最常见和最明显的案例吗?首先不会提到这个吗?)
到目前为止我想出了三个解决方案:
极低效的标准库pow
和log2
功能:
int_fast16_t powlog(uint_fast16_t n)
{
return static_cast<uint_fast16_t>(pow(2, floor(log2(n))));
}
Run Code Online (Sandbox Code Playgroud)
计算后续2次幂的效率要高得多,直到我达到的数量超过我必须达到的数量:
uint_fast16_t multiply(uint_fast16_t n)
{
uint_fast16_t maxpow = 1;
while(2*maxpow <= n)
maxpow *= 2;
return maxpow;
}
Run Code Online (Sandbox Code Playgroud)
到目前为止最有效的binsearching预先计算的2的权力表:
uint_fast16_t binsearch(uint_fast16_t n)
{
static array<uint_fast16_t, 20> pows {1,2,4,8,16,32,64,128,256,512,
1024,2048,4096,8192,16384,32768,65536,131072,262144,524288};
return *(upper_bound(pows.begin(), pows.end(), n)-1);
}
Run Code Online (Sandbox Code Playgroud)
这可以进一步优化吗?可以在这里使用的任何技巧?
我使用的完整基准:
#include <iostream>
#include <chrono>
#include <cmath>
#include <cstdint>
#include <array>
#include <algorithm>
using namespace std;
using namespace chrono;
uint_fast16_t powlog(uint_fast16_t n)
{
return static_cast<uint_fast16_t>(pow(2, floor(log2(n))));
}
uint_fast16_t multiply(uint_fast16_t n)
{ …
Run Code Online (Sandbox Code Playgroud) 这个简单的C代码首先创建一个0xFFFFFF元素的数组,然后传递两次,测量每次传递所花费的时间:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define TESTSIZ 0xffffff
char testcases[TESTSIZ];
void gentestcases(void)
{
size_t i = 0;
while(i < TESTSIZ)
testcases[i++] = rand()%128;
return;
}
long long time_elapsed(struct timespec beg, struct timespec end)
{
if(end.tv_nsec < beg.tv_nsec) {
end.tv_nsec += 1000000000;
end.tv_sec--;
}
return 1000000000ll*(end.tv_sec-beg.tv_sec) + end.tv_nsec-beg.tv_nsec;
}
long long test( int(*func)(int) )
{
struct timespec beg, end;
clock_gettime(CLOCK_MONOTONIC, &beg);
int volatile sink;
size_t i = 0;
while(i < TESTSIZ)
sink = islower(testcases[i++]);
clock_gettime(CLOCK_MONOTONIC, &end);
return …
Run Code Online (Sandbox Code Playgroud) 让我们引用numpy手册:https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html#advanced-indexing
当选择对象obj是非元组序列对象,ndarray(数据类型为integer或bool)或具有至少一个序列对象或ndarray(数据类型为integer或bool)的元组时,将触发高级索引.高级索引有两种类型:整数和布尔值.
高级索引始终返回数据的副本(与返回视图的基本切片形成对比).
然后对高级索引返回的内容进行操作永远不应该修改原始数组.事实上:
import numpy as np
arr = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
indexes = np.array([3, 6, 4])
slicedArr = arr[indexes]
slicedArr *= 5
arr
Run Code Online (Sandbox Code Playgroud)
这打印:
array([ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
Run Code Online (Sandbox Code Playgroud)
但是,情况似乎并非总是如此.奇怪的是,如果我不保存[]
操作符返回的任何中间变量,我会以某种方式在原始数组上操作.请考虑这个例子:
import numpy as np
arr = np.array([0, 10, 20, 30, 40, 50, 60, 70, 80, 90])
indexes = np.array([3, 6, 4])
arr[indexes] *= 5
arr
Run Code Online (Sandbox Code Playgroud)
这打印:
array([ 0, 10, 20, …
Run Code Online (Sandbox Code Playgroud) main = do
input <- sequence [getLine, getLine, getLine]
mapM_ print input
Run Code Online (Sandbox Code Playgroud)
让我们看看这个程序的实际效果:
m@m-X555LJ:~$ runhaskell wtf.hs
asdf
jkl
powe
"asdf"
"jkl"
"powe"
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,这里似乎没有懒惰。取而代之getLine
的是,急切地评估所有3个值,将读取的值存储在内存中,然后而不是在此之前将所有值打印出来。
比较一下:
main = do
input <- fmap lines getContents
mapM_ print input
Run Code Online (Sandbox Code Playgroud)
让我们看一下实际情况:
m@m-X555LJ:~$ runhaskell wtf.hs
asdf
"asdf"
lkj
"lkj"
power
"power"
Run Code Online (Sandbox Code Playgroud)
完全不同的东西。行被一一读取并一一打印。这对我来说很奇怪,因为我看不到这两个程序之间有什么区别。
从LearnYouAHaskell:
当I / O操作所使用,
sequenceA
是同样的事情sequence
!它获取I / O操作的列表,并返回将执行这些操作中的每个操作的I / O操作,并以结果的形式列出这些I / O操作的结果。这是因为要将一个[IO a]
值转换为一个IO [a]
值,以使一个I / O操作在执行时产生结果列表,所以所有这些I / O操作都必须先进行排序,以便在评估时依次执行。被迫。如果不执行I / O操作,则无法获得结果。
我糊涂了。我不需要执行所有IO操作就可以得到一个结果。
该书前面几段显示了以下内容的定义sequence
:
Run Code Online (Sandbox Code Playgroud)sequenceA :: …
我是对的,这段代码引入了未定义的行为?
#include <stdio.h>
#include <stdlib.h>
FILE *f = fopen("textfile.txt", "rb");
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); //same as rewind(f);
char *string = malloc(fsize + 1);
fread(string, fsize, 1, f);
fclose(f);
string[fsize] = 0;
Run Code Online (Sandbox Code Playgroud)
我之所以要问的是,这段代码是作为以下问题的一个被接受且高度评价的答案发布的:C编程:如何将整个文件内容读入缓冲区
但是,根据以下文章:如何在C++中读取整个文件到内存中(尽管它的标题,它也处理C,所以坚持我):
假设您正在编写C,并且您有
FILE*
(您知道指向文件流,或者至少是可搜索流),并且您想要确定在缓冲区中分配多少个字符来存储流的全部内容.你的第一直觉可能是编写这样的代码:Run Code Online (Sandbox Code Playgroud)// Bad code; undefined behaviour fseek(p_file, 0, SEEK_END); long file_size = ftell(p_file);
似乎是合法的.但后来你开始变得怪异了.有时报告的大小大于磁盘上的实际文件大小.有时它与实际文件大小相同,但您读入的字符数不同.这到底是怎么回事?
有两个答案,因为它取决于文件是以文本模式还是以二进制模式打开.
万一你不知道区别:在默认模式 - 文本模式 - 在某些平台上,某些字符在阅读过程中会以各种方式被翻译.最着名的是,在Windows上,新行在
\r\n
写入文件时会被翻译,并在读取时以其他方式翻译.换句话说,如果文件包含Hello\r\nWorld
,则将其读作Hello\nWorld
; 文件大小为12个字符,字符串大小为11.鲜为人知的是0x1A
(或Ctrl-Z
)被解释为文件的结尾,因此如果文件包含Hello\x1AWorld
,则将其读作Hello
.此外,如果内存中的字符串是,Hello\x1AWorld …
阅读http://learnyouahaskell.com/functors-applicative-functors-and-monoids#applicative-functors之后,我可以提供一个将函数用作应用函子的示例:
比方说res
是4个参数和功能fa
,fb
,fc
,fd
是采取单一参数的所有功能。然后,如果我没记错的话,此适用表达式:
f <$> fa <*> fb <*> fc <*> fd $ x
Run Code Online (Sandbox Code Playgroud)
与此非特殊表达式的含义相同:
f (fa x) (fb x) (fc x) (fd x)
Run Code Online (Sandbox Code Playgroud)
啊。我花了很多时间来理解为什么会这样,但是-在一张纸上放着我的笔记的帮助下-我应该能够证明这一点。
然后,我阅读了http://learnyouahaskell.com/for-a-few-monads-more#reader。我们再次以monadic语法重新介绍了这些内容:
do
a <- fa
b <- fb
c <- fc
d <- fd
return (f a b c d)
Run Code Online (Sandbox Code Playgroud)
尽管我需要另一张A4笔记来证明这一点,但我现在非常有信心,这也意味着相同:
f (fa x) (fb x) (fc x) (fd x)
Run Code Online (Sandbox Code Playgroud)
我糊涂了。为什么?这有什么用?
或者,更准确地说:在我看来,这只是复制了函数的功能作为应用程序,但语法更为冗长。
因此,您能否举一个例子,说明Reader monad能否像应用程序那样起作用?
其实,我也想问问有什么用任何这些二:应用性功能或阅读器单子-因为同时能够同样的论点适用于四种功能(fa
,fb
,fc
,fd …
c ×4
arrays ×3
c++ ×3
haskell ×2
applicative ×1
copy ×1
file-read ×1
input ×1
malloc ×1
memory-leaks ×1
monads ×1
numpy ×1
optimization ×1
performance ×1
posix ×1
python ×1
reader-monad ×1
recursion ×1
sequence ×1
stream ×1
terminate ×1
vector ×1
volatile ×1