유닉스에서 디렉토리 다루기

작성자 : 김문규
최초 작성일 : 2009. 1.21

1. 들어가며
서버 프로그래밍이든 클라이언트 프로그래밍이든 중요하게 다루어 지는 부분은 파일 시스템을 액세스해서 로컬 자원의 정보를 획득하는 것이 아닐까요?
대부분의 프로그래밍 책에서 파일을 열고 닫는 것을 많이 다룹니다. 그런데, 디렉토리에 대한 내용은 많이 보지 못한 것 같습니다.

그래서, 이번 포스트의 주제는 '유닉스에서 디렉토리 다루기' 입니다.

2. 디렉토리 다루기
특정 디렉토리부터 하위 디렉토리에 있는 파일 또는 디렉토리를 검색하는 알고리즘을 생각해 보겠습니다.
1) 현재 디렉토리에 존재하는 모든 파일 검색
2) 검색된 항목이 파일이면 다음
3) 검색된 항목이 디렉토리이면 1)로 가서 다시 검색

이를 구현시에는 다음과 같은 기능이 필요합니다.
1) 현재 디렉토리의 파일 리스팅
2) 리스팅된 파일이 일반 파일인지 디렉토리인지 구분하기
3) 재귀 함수 호출

이번 주제에 맞게 1), 2)에 대해서 간단한 예제와 함께 알아 보겠습니다.

1)디렉토리 리스팅 (Directory Listing)

디렉토리 리스팅을 위해서는 다음과 같은 구조체와 함수들을 사용하면 됩니다.

#include <dirent.h>

struct   dirent
{
    long                  d_ino;                                 // inode 넘버
    off_t                  d_off;                                 // offset
    unsigned short   d_reclen;                          // d_name 길이
    char                  d_name[NAME_MAX+1];     // 파일이름
}

DIR*  opendir(const  char*  name);                 // 열기
int   closedir(DIR*  dp);                                    // 닫기
struct  dirent*  readdir(DIR*  dp);                    // 읽기

간단한 예제 입니다.
#include <stdio.h>
#include <dirent.h>
int main (void)
{  
    DIR *pDir = NULL;
    dirent *pFile = NULL;
    pDir = opendir(".");
    if(!pDir) {
        printf("ERROR\n");
    }
    while( (pFile = readdir(pDir)) != NULL )
    {
        printf("%s\n", pFile->d_name);
    }
    closedir(pDir);
    return 0;


2) 파일 속성 알아내기

파일 속성을 알아내기 위해서는 다음과 같은 구조체와 함수들을 사용하면 됩니다.

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

// 입력 변수만 조금 다를 뿐 기능은 같습니다.
int stat(const char *file_name, struct stat *buf);
int fstat(int filedes, struct stat *buf);
int lstat(const char *file_name, struct stat *buf);

struct stat
{
    dev_t         st_dev;      /* device */
    ino_t         st_ino;      /* inode */
    mode_t        st_mode;     /* protection */
    nlink_t       st_nlink;    /* number of hard links */
    uid_t         st_uid;      /* user ID of owner */
    gid_t         st_gid;      /* group ID of owner */
    dev_t         st_rdev;     /* device type (if inode device) */
    off_t         st_size;     /* total size, in bytes */
    unsigned long st_blksize;  /* blocksize for filesystem I/O */
    unsigned long st_blocks;   /* number of blocks allocated */
    time_t        st_atime;    /* time of last access */
    time_t        st_mtime;    /* time of last modification */
    time_t        st_ctime;    /* time of last change */
};

모든 필드가 각각의 의미를 가지고 있지만 이번 포스트에서는 관심 있는 플래그는 st_mode 입니다. 이 값이 파일의 성격을 알려주는 플래그이거든요.

이 값은 다음의 매크로를 이용해서 확인 가능합니다.
S_ISLNK(m)  is it a symbolic link?
S_ISREG(m)  regular file?
S_ISDIR(m)  directory?
S_ISCHR(m)  character device?
S_ISBLK(m)  block device?
S_ISFIFO(m) fifo?
S_ISSOCK(m) socket?

예제 코드로 설명한 내용을 확인해 보겠습니다.
#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <string.h>
int main (void)
{  
    DIR *pDir = NULL;
    dirent *pFile = NULL;
    struct stat buf;
    pDir = opendir(".");
    if(!pDir) {
        printf("ERROR\n");
    }
    while( (pFile = readdir(pDir)) != NULL )
    {
        memset(&buf, 0, sizeof(struct stat));
        lstat(pFile->d_name, &buf);                    // buf에 stat 정보 저장
        if(S_ISDIR(buf.st_mode)) printf("[DIR]%s\n", pFile->d_name);
        else if(S_ISREG(buf.st_mode)) printf("[FILE]%s\n", pFile->d_name);
        else printf("[ELSE]%s\n", pFile->d_name);
    }
    closedir(pDir);
    return 0;
}  

3. 마치며
이 방법은 유닉스와 리눅스에서만 사용가능 합니다. 흠흠. 기왕이면 윈도우에서도 사용가능 했으면 좋았을 텐데요.
그럼 즐프하세요.


'Linux > C/C++' 카테고리의 다른 글

linux와 Windows의 파일 정보 접근  (0) 2012.07.10
linux GetTickCount  (0) 2012.07.10
Configuration module to update in a file  (0) 2012.07.02
Comparing floating point numbers  (0) 2012.06.18
va_start, va_arg, va_end  (0) 2012.06.08



isqms_BufferHandler_ConfigurationUpdate.tar


고려 사항 :

파일을 1000단위로 읽고 힙메모리에 저장한다. (하드 코딩)

퍼포먼스 테스트를 수행하지 않았다.

fgets의 동작을 정확하게 이해하지 못했다.


fread 에 이상현상 발견

이유 없이 마지막 불 특정 길이의 스트링 구간이 반복 저장 출력됨


수정버젼




Comparing floating point numbers

Bruce Dawson

This article is obsolete. Its replacement - which will fix some errors and better explain the relevant issues - is being crafted as a multi-part series here. Please update your links.

Ultimately this article will go away, once the series of articles is complete.

I mean it. Some of the problems with this code include aliasing problems, integer overflow, and an attempt to extend the ULPs based technique further than really makes sense. The series of articles listed above covers the whole topic, but the key article that demonstrates good techniques for floating-point comparisons can be found here. This article also includes a cool demonstration, using sin(double(pi)), of why the ULPs technique and other relative error techniques breaks down around zero.

In short, stop reading. Click this link.













Okay, you've been warned. The remainder of this article exists purely for historical reasons.

Comparing for equality

Floating point math is not exact. Simple values like 0.2 cannot be precisely represented using binary floating point numbers, and the limited precision of floating point numbers means that slight changes in the order of operations can change the result. Different compilers and CPU architectures store temporary results at different precisions, so results will differ depending on the details of your environment. If you do a calculation and then compare the results against some expected value it is highly unlikely that you will get exactly the result you intended.

In other words, if you do a calculation and then do this comparison:

if (result == expectedResult)

then it is unlikely that the comparison will be true. If the comparison is true then it is probably unstable – tiny changes in the input values, compiler, or CPU may change the result and make the comparison be false.

Comparing with epsilon – absolute error

Since floating point calculations involve a bit of uncertainty we can try to allow for this by seeing if two numbers are ‘close’ to each other. If you decide – based on error analysis, testing, or a wild guess – that the result should always be within 0.00001 of the expected result then you can change your comparison to this:

if (fabs(result - expectedResult) < 0.00001)

The maximum error value is typically called epsilon.

Absolute error calculations have their place, but they aren’t what is most often used. When talking about experimental error it is more common to specify the error as a percentage. Absolute error is used less often because if you know, say, that the error is 1.0 that tells you very little. If the result is one million then an error of 1.0 is great. If the result is 0.1 then an error of 1.0 is terrible.

With the fixed precision of floating point numbers in computers there are additional considerations with absolute error. If the absolute error is too small for the numbers being compared then the epsilon comparison may have no effect, because the finite precision of the floats may not be able to represent such small differences.

Let's say you do a calculation that has an expected answer of about 10,000. Because floating point math is imperfect you may not get an answer of exactly 10,000 - you may be off by one or two in the least significant bits of your result. If you're using 4-byte floats and you're off by one in the least significant bit of your result then instead of 10,000 you'll get +10000.000977. So we have:

float expectedResult = 10000;

float result = +10000.000977; // The closest 4-byte float to 10,000 without being 10,000

float diff = fabs(result - expectedResult);

diff is equal to 0.000977, which is 97.7 times larger than our epsilon. So, our comparison tells us that result and expectedResult are not nearly equal, even though they are adjacent floats! Using an epsilon value 0.00001 for float calculations in this range is meaningless – it’s the same as doing a direct comparison, just more expensive.

Absolute error comparisons have value. If the range of the expectedResult is known then checking for absolute error is simple and effective. Just make sure that your absolute error value is larger than the minimum representable difference for the range and type of float you’re dealing with.

Comparing with epsilon – relative error

An error of 0.00001 is appropriate for numbers around one, too big for numbers around 0.00001, and too small for numbers around 10,000. A more generic way of comparing two numbers – that works regardless of their range, is to check the relative error. Relative error is measured by comparing the error to the expected result. One way of calculating it would be like this:

relativeError = fabs((result - expectedResult) / expectedResult);

If result is 99.5, and expectedResult is 100, then the relative error is 0.005.

Sometimes we don’t have an ‘expected’ result, we just have two numbers that we want to compare to see if they are almost equal. We might write a function like this:

// Non-optimal AlmostEqual function - not recommended.

bool AlmostEqualRelative(float A, float B, float maxRelativeError)

{

if (A == B)

return true;

float relativeError = fabs((A - B) / B);

if (relativeError <= maxRelativeError)

return true;

return false;

}

The maxRelativeError parameter specifies what relative error we are willing to tolerate. If we want 99.999% accuracy then we should pass a maxRelativeError of 0.00001.

The initial comparison for A == B may seem odd – if A == B then won’t relativeError be zero? There is one case where this will not be true. If A and B are both equal to zero then the relativeError calculation will calculate 0.0 / 0.0. Zero divided by zero is undefined, and gives a NAN result. A NAN will never return true on a <= comparison, so this function will return false if A and B are both zero (on some platforms where NAN comparisons are not handled properly this function might return true for zero, but it will then return true for all NAN inputs as well, which makes this poor behavior to count on).

The trouble with this function is that AlmostEqualRelative(x1, x2, epsilon) may not give the result as AlmostEqualRelative(x2, x1, epsilon), because the second parameter is always used as the divisor. An improved version of AlmostEqualRelative would always divide by the larger number. This function might look like this;

// Slightly better AlmostEqual function – still not recommended

bool AlmostEqualRelative2(float A, float B, float maxRelativeError)

{

if (A == B)

return true;

float relativeError;

if (fabs(B) > fabs(A))

relativeError = fabs((A - B) / B);

else

relativeError = fabs((A - B) / A);

if (relativeError <= maxRelativeError)

return true;

return false;

}

Even now our function isn’t perfect. In general this function will behave poorly for numbers around zero. The positive number closest to zero and the negative number closest to zero are extremely close to each other, yet this function will correctly calculate that they have a huge relative error of 2.0. If you want to count numbers near zero but of opposite sign as being equal then you need to add a maxAbsoluteError check also. The function would then return true if either the absoluteError or the relativeError were smaller than the maximums passed in. A typical value for this backup maxAbsoluteError would be very small – FLT_MAX or less, depending on whether the platform supports subnormals.

// Slightly better AlmostEqual function – still not recommended

bool AlmostEqualRelativeOrAbsolute(float A, float B,

float maxRelativeError, float maxAbsoluteError)

{

if (fabs(A - B) < maxAbsoluteError)

return true;

float relativeError;

if (fabs(B) > fabs(A))

relativeError = fabs((A - B) / B);

else

relativeError = fabs((A - B) / A);

if (relativeError <= maxRelativeError)

return true;

return false;

}

Comparing using integers

There is an alternate technique for checking whether two floating point numbers are close to each other. Recall that the problem with absolute error checks is that they don’t take into consideration whether there are any values in the range being checked. That is, with an allowable absolute error of 0.00001 and an expectedResult of 10,000 we are saying that we will accept any number in the range 9,999.99999 to 10,000.00001, without realizing that when using 4-byte floats there is only one representable float in that range – 10,000. Wouldn’t it be handy if we could easily specify our error range in terms of how many floats we want in that range? That is, wouldn’t it be convenient if we could say “I think the answer is 10,000 but since floating point math is imperfect I’ll accept the 5 floats above and the 5 floats below that value.”

It turns out there is an easy way to do this.

The IEEE float and double formats were designed so that the numbers are “lexicographically ordered”, which – in the words of IEEE architect William Kahan means “if two floating-point numbers in the same format are ordered ( say x < y ), then they are ordered the same way when their bits are reinterpreted as Sign-Magnitude integers.”

This means that if we take two floats in memory, interpret their bit pattern as integers, and compare them, we can tell which is larger, without doing a floating point comparison. In the C/C++ language this comparison looks like this:

if (*(int*)&f1 < *(int*)&f2)

This charming syntax means take the address of f1, treat it as an integer pointer, and dereference it. All those pointer operations look expensive, but they basically all cancel out and just mean ‘treat f1 as an integer’. Since we apply the same syntax to f2 the whole line means ‘compare f1 and f2, using their in-memory representations interpreted as integers instead of floats’.

Kahan says that we can compare them if we interpret them as sign-magnitude integers. That’s unfortunate because most processors these days use twos-complement integers. Effectively this means that the comparison only works if one or more of the floats is positive. If both floats are negative then the sense of the comparison is reversed – the result will be the opposite of the equivalent float comparison. Later we will see that there is a handy technique for dealing with this inconvenience.

Because the floats are lexicographically ordered that means that if we increment the representation of a float as an integer then we move to the next float. In other words, this line of code:

(*(int*)&f1) += 1;

will increment the underlying representation of a float and, subject to certain restrictions, will give us the next float. For a positive number this means the next larger float, for a negative number this means the next smaller float. In both cases it gives us the next float farther away from zero.

We can apply this logic in reverse also. If we subtract the integer representations of two floats then that will tell us how close they are. If the difference is zero, they are identical. If the difference is one, they are adjacent floats. In general, if the difference is n then there are n-1 floats between them.

The chart below shows some floating point numbers and the integer stored in memory that represents them. It can be seen in this chart that the five numbers near 2.0 are represented by adjacent integers. This demonstrates the meaning of subtracting integer representations, and also shows that there are no floats between 1.99999988 and 2.0.

Representation

Float value

Hexadecimal

Decimal

+1.99999976

0x3FFFFFFE

1073741822

+1.99999988

0x3FFFFFFF

1073741823

+2.00000000

0x40000000

1073741824

+2.00000024

0x40000001

1073741825

+2.00000048

0x40000002

1073741826

With this knowledge of the floating point format we can write this revised AlmostEqual implementation:

// Initial AlmostEqualULPs version - fast and simple, but

// some limitations.

bool AlmostEqualUlps(float A, float B, int maxUlps)

{

assert(sizeof(float) == sizeof(int));

if (A == B)

return true;

int intDiff = abs(*(int*)&A - *(int*)&B);

if (intDiff <= maxUlps)

return true;

return false;

}

It’s certainly a lot simpler, especially when you look at all the divides and calls to fabs() that it’s not doing!

The last parameter to this function is different from the previous AlmostEqual. Instead of passing in maxRelativeError as a ratio we pass in the maximum error in terms of Units in the Last Place. This specifies how big an error we are willing to accept in terms of the value of the least significant digit of the floating point number’s representation. maxUlps can also be interpreted in terms of how many representable floats we are willing to accept between A and B. This function will allow maxUlps-1 floats between A and B.

If two numbers are identical except for a one-bit difference in the last digit of their mantissa then this function will calculate intDiff as one.

If one number is the maximum number for a particular exponent – perhaps 1.99999988 – and the other number is the smallest number for the next exponent – 2.0 – then this function will again calculate intDiff as one.

In both cases the two numbers are the closest floats there are.

There is not a completely direct translation between maxRelativeError and maxUlps. For a normal float number a maxUlps of 1 is equivalent to a maxRelativeError of between 1/8,000,000 and 1/16,000,000. The variance is because the accuracy of a float varies slightly depending on whether it is near the top or bottom of its current exponent’s range. This can be seen in the chart of numbers near 2.0 – the gap between numbers just above 2.0 is twice as big as the gap between numbers just below 2.0.

Our AlmostEqualUlps function starts by checking whether A and B are equal – just like AlmostEqualRelative did, but for a different reason that will be discussed below.

Compiler issues

In our last version of AlmostEqualUlps we use pointers and casting to tell the compiler to treat the in-memory representation of a float as an int. There are a couple of things that can go wrong with this. One risk is that int and float might not be the same size. A float should be 32 bits, but an int can be almost any size. This is certainly something to be aware of, but every modern compiler that I am aware of has 32-bit ints. If your compiler has ints of a different size, find a 32-bit integral type and use it instead.

Another complication comes from aliasing optimizations. Strictly speaking the C/C++ standard says that the compiler can assume that different types do not overlap in memory (with a few exceptions such as char pointers). For instance, it is allowed to assume that a pointer to an int and a pointer to a float do not point to overlapping memory. This opens up lots of worthwhile optimizations, but for code that violates this rule—which is quite common—it leads to undefined results. In particular, some versions of g++ default to very strict aliasing rules, and don’t like the techniques used in AlmostEqualUlps.

Luckily g++ knows that there will be a problem, and it gives this warning:

warning: dereferencing type-punned pointer will break strict-aliasing rules

There are two possible solutions if you encounter this problem. Turn off the strict aliasing option using the -fno-strict-aliasing switch, or use a union between a float and an int to implement the reinterpretation of a float as an int. The documentation for -fstrict-aliasing gives more information.

Complications

Floating point math is never simple. AlmostEqualUlps doesn’t properly deal with all the peculiar types of floating point numbers. Whether it deals with them well enough depends on how you want to use it, but an improved version will often be needed.

IEEE floating point numbers fall into a few categories:

  • Zeroes
  • Subnormals
  • Normal numbers
  • Infinities
  • NANs

Zeroes

AlmostEqual is designed to deal with normal numbers, and it is there that it behaves its best. Its first problem is when dealing with zeroes. IEEE floats can have both positive and negative zeroes. If you compare them as floats they are equal, but their integer representations are quite different – positive 0.0 is an integer zero, but negative zero is 0x80000000! (in decimal this is -2147483648). The chart below shows the positive and negative floats closest to zero, together with their integer representations.

Representation

Float value

Hexadecimal

Decimal

+4.2038954e-045

0x00000003

3

+2.8025969e-045

0x00000002

2

+1.4012985e-045

0x00000001

1

+0.00000000

0x00000000

0

-0.00000000

0x80000000

-2147483648

-1.4012985e-045

0x80000001

-2147483647

-2.8025969e-045

0x80000002

-2147483646

-4.2038954e-045

0x80000003

-2147483645

In AlmostEqualUlps I deal with this by checking for A and B being exactly equal, thus handling the case where one input is positive zero and the other is negative zero. However this still isn’t perfect. With this implementation positive zero and the smallest positive subnormal will be calculated as being one ulp apart, and therefore will generally count as being equal. However negative zero and the smallest positive subnormal will be counted as being far apart, thus destroying the idea that positive and negative zero are identical.

A more general way of handling negative numbers is to adjust them so that they are lexicographically ordered as twos-complement integers instead of as signed magnitude integers. This is done by detecting negative numbers and subtracting them from 0x80000000. This maps negative zero to an integer zero representation – making it identical to positive zero – and it makes it so that the smallest negative number is represented by negative one, and downwards from there. With this change the representations of our numbers around zero look much more rational.

Remapping for twos complement

Representation

Float value

Hexadecimal

Decimal

+4.2038954e-045

0x00000003

3

+2.8025969e-045

0x00000002

2

+1.4012985e-045

0x00000001

1

+0.00000000

0x00000000

0

-0.00000000

0x00000000

0

-1.4012985e-045

0xFFFFFFFF

-1

-2.8025969e-045

0xFFFFFFFE

-2

-4.2038954e-045

0xFFFFFFFD

-3

Once we have made this adjustment we can no longer treat our numbers as IEEE floats – the values of the negative numbers will be dramatically altered – but we can compare them as ints more easily, in our new and convenient representation.

This technique has the additional advantage that now the distance between numbers can be measured across the zero boundary. That is, the smallest subnormal positive number and the smallest subnormal negative number will now compare as being very close – just a few ulps away. This is probably a good thing – it’s equivalent to adding an absolute error check to the relative error check. Code to implement this technique looks like this:

// Usable AlmostEqual function

bool AlmostEqual2sComplement(float A, float B, int maxUlps)

{

// Make sure maxUlps is non-negative and small enough that the

// default NAN won't compare as equal to anything.

assert(maxUlps > 0 && maxUlps < 4 * 1024 * 1024);

int aInt = *(int*)&A;

// Make aInt lexicographically ordered as a twos-complement int

if (aInt < 0)

aInt = 0x80000000 - aInt;

// Make bInt lexicographically ordered as a twos-complement int

int bInt = *(int*)&B;

if (bInt < 0)

bInt = 0x80000000 - bInt;

int intDiff = abs(aInt - bInt);

if (intDiff <= maxUlps)

return true;

return false;

}

Subnormals

The next potential issue is subnormals, also known as denormals. Subnormals are numbers that are so small that they cannot be normalized. This lack of normalization means that they have less precision – the closer they get to zero, the less precision they have. This means that when comparing two subnormals, an error of one ulp can imply a significant relative error – as great as 100%. However the interpretation of the ulps error as a measure of the number of representable floats between the numbers remains. Thus, this variation in the relativeError interpretation is probably a good thing – yet another advantage to this technique of comparing floating point numbers.

Infinities

IEEE floating point numbers have a special representation for infinities. These are used for overflows and for the result of divide by zeroes. The representation for infinities is adjacent to the representation for the largest normal number. Thus, the AlmostEqualUlps routine will say that FLT_MAX and infinity are almost the same. This is reasonable in some sense – after all, there are no representable floats between them – but horribly inaccurate in another sense – after all, no finite number is ‘close’ to infinity.

If treating infinity as being ‘close’ to FLT_MAX is undesirable then an extra check is needed.

NANs

IEEE floating point numbers have a series of representations for NANs. These representations – sharing an exponent with infinity but marked by their non-zero mantissa – are numerically adjacent to the infinities when compared as ints. Therefore it is possible for an infinite result, or a FLT_MAX result, to compare as being very close to a NAN. If your code produces NAN results then this could be very bad. However, two things protect against this problem. One is that most floating point code is designed to not produce NANs, and in fact most floating point code should treat NANs as an error by enabling floating point divide by zero and floating point illegal operation exceptions. The other reason this should not be an issue is that usually only one NAN value is generated. On x87 compatible processors this value is 0xFFC00000, which has a value separated by four million from the nearest infinity. This value is particularly well placed because another risk with NAN comparisons is that they could wrap around. A NAN with a value of 0xFFFFFFFF could compare as being very close to zero. The translation of negative numbers used by AlmostEqual2sComplement avoids this by moving the NANs where they can only wrap around to each other, but the NAN value 0xFFC00000 also avoids this problem since it keeps the NAN value four million ulps away from wrapping around.

One other complication is that comparisons involving NANs are always supposed to return false, but AlmostEqual2sComplement will say that two NANs are equal to each other if they have the same integer representation. If you rely on correct NAN comparisons you have to add extra checks.

Limitations

maxUlps cannot be arbitrarily large. If maxUlps is four million or greater then there is a risk of finding large negative floats equal to NANs. If maxUlps is sixteen million or greater then the largest positive floats will compare as equal to the largest negative floats.

As a practical matter such large maxUlps values should not be needed. A maxUlps of sixteen million means that numbers 100% larger and 50% smaller should count as equal. A maxUlps of four million means that numbers 25% larger and 12.5% smaller should count as equal. If these large maxUlps values are needed then separate checking for wrap-around above infinity to NANs or numbers of the opposite sign will be needed. To prevent accidental usage of huge maxUlps values the comparison routines assert that maxUlps is in a safe range.

AlmostEqual2sComplement is very reliant on the IEEE floating point math format, and assumes twos-complement integers of the same size. These limitations are the norm on the majority of machines, especially consumer machines, but there are machines out there that use different formats. For this reason, and because the techniques used are tricky and non-obvious, it is important to encapsulate the behavior in a function where appropriate documentation, asserts, and conditional checks can be placed.

Summary

AlmostEqual2sComplement is an effective way of handling floating point comparisons. Its behavior does not map perfectly to AlmostEqualRelative, but in many ways its behavior is arguably superior. To summarize, AlmostEqual2sComplement has these characteristics:

  • Measures whether two floats are ‘close’ to each other, where close is defined by ulps, also interpreted as how many floats there are in-between the numbers
  • Treats infinity as being close to FLT_MAX
  • Treats NANs as being four million ulps away from everything (assuming the default NAN value for x87), except other NANs
  • Accepts greater relative error as numbers gradually underflow to subnormals
  • Treats tiny negative numbers as being close to tiny positive numbers

If the special characteristics of AlmostEqual2sComplement are not desirable then they can selectively be checked for. A version with the necessary checks, #ifdefed for easy control of the behavior, is available here.

AlmostEqual2sComplement works best on machines that can transfer values quickly between the floating point and integer units. This often requires going through memory and can be quite slow. This function can be implemented efficiently on machines with vector units that can do integer or floating point operations on the same registers. This allows reinterpreting the values without going through memory.

The same techniques can be applied to doubles, mapping them to 64-bit integers. Because doubles have a 53-bit mantissa a one ulp error implies a relative error of between 1/4,000,000,000,000,000 and 1/8,000,000,000,000,000.

References

IEEE Standard 754 Floating Point Numbers by Steve Hollasch

Lecture Notes on the Status of IEEE Standard 754 for Binary Floating-Point Arithmetic by William Kahan

Source code for compare functions and tests

Other papers...

 

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h> 

 

char com(char *data);


int main(void)
{
 char* array[5] = {"000","123","234","456","789"};

 //가변인자에 데이타 보내기
 com(array[0],array[1],array[2],array[3],NULL);
 return 0;
}


//가변인자를 선언한 com 함수
char com(char *data,...)
{
 char *ptr;
 int a;
 int min;
 int max;

 va_list arg_ptr;

 a = atoi(data);
 min = max = a;

 // 시작 - char* data 다음 parameter 변수를 va_list에 담는다.
 va_start(arg_ptr, data);

 while(1)
 {
  //가져오기 - va_list에서 데이타 가져오기( char* 는 리턴될 가변 변수의 데이타 형입니다.)
  ptr = va_arg(arg_ptr,char*);

  //가변인자 값이 NULL이오면 반복종료
  if(!ptr) break;

   a = atoi(ptr);

   if(a < min) min = a;
   if(a > max) max = a;
 }

 // 끝 - 모든 변수를 읽은 후 정상적인 리턴을 위하여 종료 

 va_end(arg_ptr );

 

 printf("the max number = %d\n",max);
 printf("the min number = %d\n",min);
}

프로그램 라이브러리

Standard C Library (libc, -lc)

서식

#include <stdio.h>

int
printf(const char *format, ...)

int
fprintf(FILE *stream, const char *format, ...)

int
sprintf(char *str, const char *format, ...)

int
snprintf(char *str, size_t size, const char *format, ...)

int
asprintf(char **ret, const char *format, ...)
#include <stdarg.h>

int
vprintf(const char *format, va_list ap)

int
vfprintf(FILE *stream, const char *format, va_list ap)

int
vsprintf(char *str, const char *format, va_list ap)

int
vsnprintf(char *str, size_t size, const char *format, va_list ap)

int
vasprintf(char **ret, const char *format, va_list ap)

해설

printf() 패밀리의 함수는, 이하로 설명한다 format 에 따라 출력을 실시합니다. printf() (와)과 vprintf() (은)는, 표준 출력 stdout 에 출력을 실시합니다. fprintf() (와)과 vfprintf() (은)는, 지정된 출력 stream 에 출력을 실시합니다. sprintf(), snprintf(), vsprintf(), vsnprintf() (은)는, 캐릭터 캐릭터 라인 str 에 출력을 실시합니다. asprintf() (와)과 vasprintf() (은)는, malloc(3) 그리고 새로운 캐릭터 라인을 동적으로 할당합니다.

이러한 함수는, format 캐릭터 라인에 의한 제어에 따라 출력을 실시합니다. 이 캐릭터 라인은, 그 후의 인수 (또는 stdarg(3) 의 가변장 인수 기능으로 액세스 할 수 있는 인수) (을)를 출력용으로 변환하는 방법을 지정합니다.

이 함수는, 출력된 캐릭터수 (캐릭터 라인에의 출력을 종료하는, 마지막 `\0' (은)는 포함하지 않는다)를 돌려줍니다. snprintf() (와)과 vsnprintf() 의 경우만, size 의 제한이 없었다고 하면(자) 출력되었을 것이다 캐릭터수 (와 같이 캐릭터 라인의 마지막 `\0' (은)는 포함하지 않는다)를 돌려줍니다.

asprintf() (와)과 vasprintf() (은)는, 정형된 캐릭터 라인을 격납하는데 충분한 크기의 버퍼를 가리키는 포인터를 *ret (으)로 설정합니다. 할당할 수 있었던 area가 불필요하게 되었을 경우는, 이 포인터를 free(3) 에 건네주어 해방해 주세요. 충분한 area를 할당할 수 없는 경우, asprintf() (와)과 vasprintf() (은)는 -1 을 되돌려, ret (을)를 NULL 포인터로 설정합니다.

snprintf() (와)과 vsnprintf() (은)는, 최대로 size, Ns, -1 캐릭터만 출력 캐릭터 라인에 기입합니다 ( size 번째의 캐릭터는 종단의 `\0' (이)가 됩니다). 반환값이 size 인수 이상인 경우는, 캐릭터 라인을 격납하려면 단인가 지났기 때문에, 출력된 캐릭터의 일부가 파기된 것이 됩니다.

sprintf() (와)과 vsprintf() (은)는, size 하지만 무한하다라고 가정합니다.

정형 캐릭터 라인은, 0 이상의 인스트럭션으로부터 구성되어 있습니다. 이 인스트럭션에는, 출력 스트림로 변경되지 않고 카피된다 통상 캐릭터 ( % 이외), 및 0 이상의 후속의 인수를 꺼내는 변환 지정이 있습니다. 각각의 변환 지정은, % 캐릭터로부터 시작됩니다. 인수는, (형태 확장의 뒤에) 변환 지시자에게 적절히 대응할 필요가 있습니다. % 의 후에는, 이하가 차례로 나타납니다.

  • 후에 $ 하지만 계속되는 10 진수 캐릭터 라인으로부터 구성되어 다음에 액세스 하는 인수를 지정하는 임의의 필드. 이 필드를 지정하지 않으면 마지막에 액세스 되었다 인수에 계속되는 인수가 사용됩니다. 인수에는 1 (으)로부터 시작되는 번호가 붙습니다. 서식 지정 캐릭터 라인으로, 액세스 할 수 없는 인수를 액세스 할 수 있는 인수에 점재하는 경우, 결과는 부정이 됩니다.
  • 0 개 이상의 이하의 플래그

    값을 "대체 형식" (으)로 변환하는 것을 지정한다 # 캐릭터. c, d, i, n, p, s, 및 u 변환의 경우, 이 옵션은 효과를 발휘하지 않습니다. o 변환의 경우는, 수치의 정밀도가 올라, 출력 캐릭터 라인의 최초의 캐릭터가 0 이 됩니다 (명확한 정밀도의 0 으로 0 이 출력되는 경우를 제외하다). x 변환과 X 변환의 경우는, 0 이외의 결과의 전에 캐릭터 라인 `0x' ( X 변환의 경우는 `0X') 하지만 붙습니다. e, E, f, g, 및 G 변환의 경우는, 소수점 이하가 없어도 소수점이 결과에 항상 포함됩니다 (통상의 경우, 소수점 이하가 있는 경우에 한해, 변환 결과에 소수점이 붙습니다). g G 변환의 경우는, 후속의 0 이 통상의 경우와 같이 결과로부터 삭제되지 않습니다.

    0 (제로) 캐릭터의 패딩을 지정한다. n 변환을 제외한 모든 변환에서는, 변환치의 왼쪽으로 공백은 아니고 0 이 붙습니다. 수치 변환 ( d, i, o, u, i, x, 및 X) 그리고 정밀도가 지정되어 있는 경우, 0 플래그는 무시됩니다.

    부의 필드폭을 나타낸다 - 플래그는 변환된 값이 필드 경계의 왼쪽에서 가지런히 할 수 있는 일을 나타냅니다. n 변환 이외에서는, 변환치의 왼쪽으로 공백이나 0 이 붙는 것이 아니라, 변환치의 오른쪽으로 공백이 붙습니다. - (와)과 0 (을)를 양쪽 모두 지정했을 경우는 0 하지만 무효가 됩니다.

    공백. 부호 첨부 변환 ( d, e, E, f, g, G, 및 i) 그리고 작성되는 정의 수치의 전에 공백이 남습니다.

    + 캐릭터. 부호 첨부 변환으로 작성되는 수치의 전에 항상 부호가 붙습니다. + (와)과 공백을 양쪽 모두 지정했을 경우는 공백이 무효가 됩니다.
  • 임의의 10 진수 캐릭터 라인. 최저 필드폭을 지정합니다. 변환치의 캐릭터수가 필드의 폭보다 적은 경우는, 왼쪽으로 공백이 붙어 (왼쪽 가지런히 하고 플래그를 지정했을 경우는 오른쪽으로 공백이 붙어) 필드의 폭에 맞출 수 있습니다.
  • 피리어드 . 의 다음에 임의의 숫자 캐릭터 라인이 계속되는 형식의 정밀도. 숫자 캐릭터 라인을 생략 했을 경우, 정밀도는 0 이 됩니다. d, i, o, u, x, 및 X 변환에서는, 이 정밀도의 최저 자리수가 출력됩니다. e, E, 및 f 변환에서는, 소수점 이하에 이 정밀도의 자리수가 출력됩니다. g G 변환에서는, 이 정밀도의 최대 유효 자리수가 출력됩니다. s 변환에서는, 이 정밀도의 최대 캐릭터수가 캐릭터 라인으로부터 출력됩니다.
  • 옵션 캐릭터 h d, i, o, u, x, 및 X 변환이 short int 인수인가 unsigned short int 인수에 대응하는 것, 또는 후의 n 변환이 short int 인수의 포인터에 대응하는 것을 지정합니다.
  • 옵션 캐릭터 l (소문자의 L). 후의 d, i, o, u, x, 및 X 변환이 long int 인수인가 unsigned long int 인수의 포인터에 적용되는 것, 또는 후의 n 변환이 long int 인수의 포인터에 대응하는 것을 지정합니다.
  • 옵션 캐릭터 ll (소문자의 L 가 2 개). 후의 d, i, o, u, x, 및 X 변환이 long long int 인수인가 unsigned long long int 인수에 대응하는 것, 또는 후의 n 변환이 long long int 인수의 포인터에 대응하는 것을 지정합니다.
  • 옵션 캐릭터 q, d, i, o, u, x, 및 X 변환이 quad int 인수인가 unsigned quad int 인수에 대응하는 것, 또는 후의 n 변환이 quad int 인수의 포인터에 대응하는 것을 지정합니다.
  • 옵션 캐릭터 L e, E, f, g, 및 G 변환이 long double 인수에 대응하는 것을 지정합니다.
  • 적용하는 변환의 형태를 지정하는 캐릭터.

필드폭이나 정밀도, 또는 그 양쪽 모두는, asterisk `*' , 또는 숫자 캐릭터 라인 대신에 1 개(살) 이상의 10 진수와 `$' 하지만 계속되는 asterisk로 지정할 수 있습니다. 이 경우, int 인수는 필드폭이나 정밀도를 제공합니다. 부의 필드폭은, 정의 필드폭이 계속되는 왼쪽 가지런히 하고 플래그로서 다루어집니다. 부의 정밀도는, 결핍 하고 있는 것으로서 다루어집니다. 1 개의 서식 인스트럭션에 위치 인수 (nn$) (와)과 위치 이외의 인수가 혼재하고 있는 경우, 결과는 미정도리가 됩니다.

변환 지시자와 그 의미는 다음과 같습니다.

diouxX
  int 인수 (또는 적절한 가변 인수)가, 부호 첨부 10 진 ( d (와)과 i) , 부호 없음 8 진 ( o) , 부호 없음 10 진 ( u) , 부호 없음 16 진 ( x (와)과 X) 에 변환됩니다. x 변환에는 캐릭터 abcdef , X 변환에는 캐릭터 ABCDEF 하지만 사용됩니다. 정밀도는, 출력하는 최저 자리수를 지정합니다. 변환치로 적은 자리수 밖에 필요없는 경우는, 왼쪽으로 0 이 붙습니다.
DOU long int 인수가, 부호 첨부 10 진, 부호 없음 8 진, 부호 없음 10 진에, 각각의 형식이 ld, lo, 및 lu 인것 같이 변환됩니다. 이 변환 캐릭터에는 문제가 있으므로, 최종적으로는 출력되지 않습니다.
eE double 인수를 말 수 있어 [-]d . ddd e \*[Pm]dd 의 스타일에 변환됩니다. 소수점 이상은 1 자리수로, 소수점 이하의 자리수는 정밀도와 동일해집니다. 정밀도가 지정되어 있지 않은 경우는 6 이 가정됩니다. 정밀도가 0 인 경우, 소수점은 출력되지 않습니다. E 변환에서는, 캐릭터 E ( e (은)는 아니다)가 사용되어 지수가 도입됩니다. 지수에는, 최저 2 자리수가 항상 포함됩니다. 값이 0 인 경우, 지수는 00 이 됩니다.
f double 인수를 말 수 있어 [-]ddd . ddd, 의 스타일로 10 진에 변환됩니다. 소수점 이하의 자리수는, 정밀도 지정에 동일해집니다. 정밀도가 지정되어 있지 않은 경우는 6 이 가정됩니다. 정밀도가 0 인 경우, 소수점은 출력되지 않습니다. 소수점이 출력되는 경우는, 소수점 이상으로 최저 1 자리수가 출력됩니다.
gG double 인수가, 스타일 f 인가 e ( G 변환의 경우는 E) 그리고 변환됩니다. 정밀도는 유효 자리수를 지정합니다. 정밀도가 지정되어 있지 않은 경우는 6 이 가정됩니다. 정밀도가 0 인 경우는 1 으로서 다루어집니다. 변환 후의 지수가 -4 보다 작은가 정밀도 이상인 경우는, 스타일 e 하지만 사용됩니다. 후속의 0 은, 결과의 소수부로부터 삭제됩니다. 소수점은, 소수점 이하에 최악이어도 1 자리수 있는 경우에 출력됩니다.
c int 인수가 unsigned char 에 변환되어 변환된 캐릭터가 출력됩니다.
s char * 인수가, 캐릭터형의 배열을 가리키는 포인터 (캐릭터 라인에의 포인터)(으)로 간주해집니다. 배열의 캐릭터는, 마지막 눌 캐릭터까지 출력됩니다 ( NULL 캐릭터는 출력되지 않습니다). 정밀도가 지정되어 있는 경우, 지정된 수이상은 출력되지 않기 때문에, NULL 캐릭터는 필요 없습니다. 정밀도가 지정되어 있지 않은 경우, 또는 정밀도가 배열의 사이즈 이상인 경우, 배열의 마지막에는 눌 캐릭터가 필요합니다.
p void * 포인터 인수가, 16 진으로 `(%#x' 인가 `%#lx' 에서의 같게) 출력됩니다.
n 지금까지 출력된 캐릭터수가, int * 포인터 인수 (또는 가변 포인터 인수) 하지만 지정하는 정수에 보존됩니다. 인수는 변환되지 않습니다.
% `%' 하지만 출력됩니다. 변환되는 인수는 없습니다. 완전한 변환 지정은 `%%' 입니다.

필드폭이 존재하지 않는 경우, 또는 필드폭이 작은 경우에서도, 필드는 잘라 버릴 수 없습니다. 변환 결과가 필드폭보다 큰 경우, 필드는 변환 결과를 수용할 수 있게 될 때까지 확장됩니다.

weekday (와)과 month 하지만 캐릭터 라인에의 포인터인 경우에 "Sunday, July 3, 10:02" 그렇다고 하는 형식에서 일자와 시각을 출력하는 경우:
#include <stdio.h>
fprintf(stdout, "%s, %s %d, %. 2d:%. 2d\n",
        weekday, month, day, hour, min);

(Pi 를 소수 제 5 위까지 출력하는 경우:

#include <math.h>
#include <stdio.h>
fprintf(stdout, "pi = %. 5f\n", 4 * atan(1.0));

128 바이트의 캐릭터 라인을 할당해, 거기에 출력하는 경우:

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
char *newfmt(const char *fmt, ...)
{
                char *p;
                va_list ap;
                if ((p = malloc(128)) == NULL)
                        return (NULL);
                va_start(ap, fmt);
                (void) vsnprintf(p, 128, fmt, ap);
                va_end(ap);
                return (p);
}

관련 항목

표준

fprintf(), printf(), sprintf(), vprintf(), vfprintf(), 및 vsprintf() 함수는, ISO/IEC 9899:1990 ("ISO C90") 에 적합하고 있습니다.

역사

asprintf() 함수와 vasprintf() 함수는, GNU C 프로그램 라이브러리에 추가되었습니다. 이것은, FreeBSD 2.2 그리고 Peter Wemm<peter@FreeBSD.org> 에 의해 실장되었습니다만, OpenBSD 2.3 그럼 후에 Todd C. Miller<Todd.Miller@courtesan.com> 의 시스템으로 옮겨놓을 수 있었습니다.

버그

변환 형식 %D, %O, 및 (은)는 표준적이 아니고, 하위 호환성을 유지하기 위해서(때문에) 제공되고 있습니다. %p 형식에 ( 0 플래그나 정밀도를 지정하는 것으로) 0 을 패딩 하는 것, %n 변환과 %p 변환으로 # 플래그를 지정하는 것, %Ld (와)과 같이 무의미한 편성은 표준적이지 않습니다. 이러한 편성은 피해 주세요.

sprintf() (와)과 vsprintf() 그럼 무한하게 긴 캐릭터 라인이 가정되므로, 호출측에서는 실제의 공간을 오버플로우 하지 않게 주의할 필요가 있습니다. 오버플로우 하지 않는 것을 프로텍션하는 것은 곤란합니다. 안전이기 때문에, 대신에 snprintf() 인터페이스를 사용해 주세요. 유감스럽지만, 이 인터페이스는 이식할 수 없습니다.


'Linux > C/C++' 카테고리의 다른 글

Configuration module to update in a file  (0) 2012.07.02
Comparing floating point numbers  (0) 2012.06.18
va_start, va_arg, va_end  (0) 2012.06.08
Local IP 가져오는 C 소스  (0) 2012.03.04
heap Memory Issue  (0) 2011.12.09
OverFlow 커뮤니티를 보다가 정말 괜찮은 소스가 있길래 옮겨둔다

FILE * fp = popen("ifconfig", "r");
            if (fp) {
                    char *p=NULL, *e; size_t n;
                    while ((getline(&p, &n, fp) > 0) && p) {
                       if (p = strstr(p, "inet addr:")) {
                            p+=10;
                            if (e = strchr(p, ' ')) {
                                 *e='\0';
                                 printf("%s\n", p);
                                 break;
                            }
                       }
                    }
            }
            pclose(fp);
heap Memory Issue Linux/C/C++ 2011. 12. 9. 10:02
어제 작업을 하면서 발견한 이슈를 기록하고자 한다

main
(
int * index;
indexClone(index);

if(index==NULL) printf("Fuck!!!! What's this!!!\n");

}

indexClone(*index)
{
index=(int *)malloc(MAXSIZE*sizeof(int);
}

위와같은 간단한 코드상에서 3가지 방법을 사용하여

main에서 결과값을 확인하였을떄

NULL이 잡힌다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

방법은 다음과 같다

1. 위와 같은 방법

2. 2차 포인트 사용

3. return을 힙메모리 주소로 던져주고 main의 index로 주소를 받는 방법

이론상으론 다 되어야 한다

안된다.

그래서 마지막으로 사용해 본 방법은 Struct를 사용해 1번 방법대로 만들었다.

된다.

거지같다 ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

아무리 생각하고 구글링해도 원인을 모르겠다

뭘까....





문제 해결 -------------- 이중포인터 사용 (내가 잘못 쓴듯)

#include <stdio.h>
#include <stdlib.h>

#define MAXSIZE 10

void indexClone(int **index)
{
    *index=(int *)malloc(MAXSIZE*sizeof(int));
}

void main(void)
{
    int *index;
   
    while(1)
    {
        usleep(10000);
       
        indexClone(&index);
        if(index==NULL)
        {
            printf("Fuck you!!\n");
            free(index);
        }
        else
        {
            printf("Ohhhh good!!\n");
            free(index);
        }
    }
       
이중 포인터로 위와같은 방법을 쓰면 해결 가능